/*============================================================================*/
/*  Copyright (C) 2009-2013,  INFRASTRUCTURE SOFTWARE CO.,LTD.
 *  
 *  All rights reserved. This software is  property. Duplication 
 *  or disclosure without  written authorization is prohibited.
 *  
 *  
 *  @file       CanTp_TX.c
 *  @brief      <Briefly describe file(one line)>
 *  
 *  <Compiler: CANTP    MCU:CANTP>
 *  
 *  @author     stanley
 *  @date       2013-4-7
 */
/*============================================================================*/


/*=======[R E V I S I O N   H I S T O R Y]====================================*/
/*  <VERSION>    <DATE>    <AUTHOR>    <REVISION LOG>
 *  V1.0.0       
 *  V1.0.1       2019-12-5 tao.yu     QAC change
 *  V1.0.2       2020-1-7  tao.yu     Commercial project problem modification
 * 
 *  
 */
/*============================================================================*/

/*=======[V E R S I O N  I N F O R M A T I O N]===============================*/
#define CANTP_TX_C_AR_MAJOR_VERSION  4
#define CANTP_TX_C_AR_MINOR_VERSION  2
#define CANTP_TX_C_AR_PATCH_VERSION  2
#define CANTP_TX_C_SW_MAJOR_VERSION  1
#define CANTP_TX_C_SW_MINOR_VERSION  0
#define CANTP_TX_C_SW_PATCH_VERSION  2

/*required CANIF version*/
#define CANTP_TX_C_CANIF_AR_MAJOR_VERSION  4
#define CANTP_TX_C_CANIF_AR_MINOR_VERSION  2

/*required PDUR version*/
#define CANTP_TX_C_PDUR_AR_MAJOR_VERSION  4
#define CANTP_TX_C_PDUR_AR_MINOR_VERSION  2

/*required DEM version*/
#define CANTP_TX_C_DEM_AR_MAJOR_VERSION  4
#define CANTP_TX_C_DEM_AR_MINOR_VERSION  2

/*required DET version*/
#define CANTP_TX_C_DET_AR_MAJOR_VERSION  4
#define CANTP_TX_C_DET_AR_MINOR_VERSION  2

/*=======[I N C L U D E S]====================================================*/
#include "CanTp.h"
#include "CanTp_Internal.h"

/*=======[V E R S I O N  C H E C K]===========================================*/
/*check version information with CanTp.h*/
#if (CANTP_TX_C_AR_MAJOR_VERSION != CANTP_H_AR_MAJOR_VERSION)
  #error "CanTp_TX.c : Mismatch in Specification Major Version with CanTp.h"
#endif
#if (CANTP_TX_C_AR_MINOR_VERSION != CANTP_H_AR_MINOR_VERSION)
  #error "CanTp_TX.c : Mismatch in Specification Minor Version with CanTp.h"
#endif
#if (CANTP_TX_C_AR_PATCH_VERSION != CANTP_H_AR_PATCH_VERSION)
  #error "CanTp_TX.c : Mismatch in Specification Patch Version with CanTp.h"
#endif
#if (CANTP_TX_C_SW_MAJOR_VERSION != CANTP_H_SW_MAJOR_VERSION)
  #error "CanTp_TX.c : Mismatch in Software Implementation Major Version with CanTp.h"
#endif
#if (CANTP_TX_C_SW_MINOR_VERSION != CANTP_H_SW_MINOR_VERSION)
  #error "CanTp_TX.c : Mismatch in Software Implementation Minor Version with CanTp.h"
#endif

/*check version information with CanTp_Internal.h*/
#if (CANTP_TX_C_AR_MAJOR_VERSION != CANTP_INTERNAL_H_AR_MAJOR_VERSION)
  #error "CanTp_TX.c : Mismatch in Specification Major Version with CanTp_Internal.h"
#endif
#if (CANTP_TX_C_AR_MINOR_VERSION != CANTP_INTERNAL_H_AR_MINOR_VERSION)
  #error "CanTp_TX.c : Mismatch in Specification Minor Version with CanTp_Internal.h"
#endif
#if (CANTP_TX_C_AR_PATCH_VERSION != CANTP_INTERNAL_H_AR_PATCH_VERSION)
  #error "CanTp_TX.c : Mismatch in Specification Patch Version with CanTp_Internal.h"
#endif
#if (CANTP_TX_C_SW_MAJOR_VERSION != CANTP_INTERNAL_H_SW_MAJOR_VERSION)
  #error "CanTp_TX.c : Mismatch in Software Implementation Major Version with CanTp_Internal.h"
#endif
#if (CANTP_TX_C_SW_MINOR_VERSION != CANTP_INTERNAL_H_SW_MINOR_VERSION)
  #error "CanTp_TX.c : Mismatch in Software Implementation Minor Version with CanTp_Internal.h"
#endif

/*check version information with CanTp_Types.h*/
#if (CANTP_TX_C_AR_MAJOR_VERSION != CANTP_TYPES_H_AR_MAJOR_VERSION)
  #error "CanTp_TX.c : Mismatch in Specification Major Version with CanTp_Types.h"
#endif
#if (CANTP_TX_C_AR_MINOR_VERSION != CANTP_TYPES_H_AR_MINOR_VERSION)
  #error "CanTp_TX.c : Mismatch in Specification Minor Version with CanTp_Types.h"
#endif
#if (CANTP_TX_C_AR_PATCH_VERSION != CANTP_TYPES_H_AR_PATCH_VERSION)
  #error "CanTp_TX.c : Mismatch in Specification Patch Version with CanTp_Types.h"
#endif
#if (CANTP_TX_C_SW_MAJOR_VERSION != CANTP_TYPES_H_SW_MAJOR_VERSION)
  #error "CanTp_TX.c : Mismatch in Software Implementation Major Version with CanTp_Types.h"
#endif
#if (CANTP_TX_C_SW_MINOR_VERSION != CANTP_TYPES_H_SW_MINOR_VERSION)
  #error "CanTp_TX.c : Mismatch in Software Implementation Minor Version with CanTp_Types.h"
#endif

/*check version information with CanTp_Cfg.h*/
#if (CANTP_TX_C_AR_MAJOR_VERSION != CANTP_CFG_H_AR_MAJOR_VERSION)
  #error "CanTp_TX.c : Mismatch in Specification Major Version with CanTp_Cfg.h"
#endif
#if (CANTP_TX_C_AR_MINOR_VERSION != CANTP_CFG_H_AR_MINOR_VERSION)
  #error "CanTp_TX.c : Mismatch in Specification Minor Version with CanTp_Cfg.h"
#endif
#if (CANTP_TX_C_AR_PATCH_VERSION != CANTP_CFG_H_AR_PATCH_VERSION)
  #error "CanTp_TX.c : Mismatch in Specification Patch Version with CanTp_Cfg.h"
#endif
#if (CANTP_TX_C_SW_MAJOR_VERSION != CANTP_CFG_H_SW_MAJOR_VERSION)
  #error "CanTp_TX.c : Mismatch in Software Implementation Major Version with CanTp_Cfg.h"
#endif
#if (CANTP_TX_C_SW_MINOR_VERSION != CANTP_CFG_H_SW_MINOR_VERSION)
  #error "CanTp_TX.c : Mismatch in Software Implementation Minor Version with CanTp_Cfg.h"
#endif

/*check version information with DEM*/
#if (CANTP_TX_C_DEM_AR_MAJOR_VERSION != DEM_H_AR_MAJOR_VERSION)
  #error "CanTp_TX.c : Mismatch in Specification Major Version with Dem.h"
#endif
#if (CANTP_TX_C_DEM_AR_MINOR_VERSION != DEM_H_AR_MINOR_VERSION)
  #error "CanTp_TX.c : Mismatch in Specification Minor Version with Dem.h"
#endif

#if (CANTP_DEV_ERROR_DETECT == STD_ON)
/*Check version information with DET*/
#if (CANTP_TX_C_DET_AR_MAJOR_VERSION != DET_H_AR_MAJOR_VERSION)
  #error "CanTp_TX.c : Mismatch in Specification Major Version with Det.h"
#endif
#if (CANTP_TX_C_DET_AR_MINOR_VERSION != DET_H_AR_MINOR_VERSION)
  #error "CanTp_TX.c : Mismatch in Specification Minor Version with Det.h"
#endif
#endif

/*Check version information with PDUR*/
#if (CANTP_TX_C_PDUR_AR_MAJOR_VERSION != PDUR_CANTP_H_AR_MAJOR_VERSION)
  #error "CanTp_TX.c : Mismatch in Specification Major Version with PduR_CanTp.h"
#endif
#if (CANTP_TX_C_PDUR_AR_MINOR_VERSION != PDUR_CANTP_H_AR_MINOR_VERSION)
  #error "CanTp_TX.c : Mismatch in Specification Minor Version with PduR_CanTp.h"
#endif

/*Check version information with CANIF*/
#if (CANTP_TX_C_CANIF_AR_MAJOR_VERSION != CANIF_H_AR_MAJOR_VERSION)
  #error "CanTp_TX.c : Mismatch in Specification Major Version with CanIf.h"
#endif
#if (CANTP_TX_C_CANIF_AR_MINOR_VERSION != CANIF_H_AR_MINOR_VERSION)
  #error "CanTp_TX.c : Mismatch in Specification Minor Version with CanIf.h"
#endif
/*=======[M A C R O S]========================================================*/
#define DLC_NUM 7u
/*=======[T Y P E   D E F I N I T I O N S]====================================*/

/*=======[E X T E R N A L   D A T A]==========================================*/

/*=======[E X T E R N A L   F U N C T I O N   D E C L A R A T I O N S]========*/

/*=======[I N T E R N A L   D A T A]==========================================*/
#include "Cantp_MemMap.h"
/*=======[I N T E R N A L   F U N C T I O N   D E C L A R A T I O N S]========*/
#define CANTP_START_SEC_CODE
#include "Cantp_MemMap.h"

/*************************************************************************/
/*
 * Brief               construct FF PCI information in local buffer for channel.
 * ServiceId           N/A
 * Sync/Async          Synchronous
 * Reentrancy          Non Reentrant
 * Param-Name[in]      ChannelIdx index of channel
 * Param-Name[out]     N/A
 * Param-Name[in/out]  N/A
 * Return              N/A
 * PreCondition        Module initialized, need to construct FF.
 * CallByAPI           CanTp_MainFunction
 */
/*************************************************************************/
static FUNC(void, CANTP_CODE)
CanTp_ConstructFFPci(uint8 ChannelIdx);

/*************************************************************************/
/*
 * Brief               construct SF PCI information in local buffer for channel.
 * ServiceId           N/A
 * Sync/Async          Synchronous
 * Reentrancy          Non Reentrant
 * Param-Name[in]      ChannelIdx index of channel
 * Param-Name[out]     N/A
 * Param-Name[in/out]  N/A
 * Return              N/A
 * PreCondition        Module initialized, need to construct SF.
 * CallByAPI           CanTp_MainFunction
 */
/*************************************************************************/
static FUNC(void, CANTP_CODE)
CanTp_ConstructSFPci(uint8 ChannelIdx);

/*************************************************************************/
/*
 * Brief               construct CF PCI information in local buffer for channel.
 * ServiceId           N/A
 * Sync/Async          Synchronous
 * Reentrancy          Non Reentrant
 * Param-Name[in]      ChannelIdx index of channel
 * Param-Name[out]     N/A
 * Param-Name[in/out]  N/A
 * Return              N/A
 * PreCondition        Module initialized, need to construct CF.
 * CallByAPI           CanTp_MainFunction
 */
/*************************************************************************/
static FUNC(void, CANTP_CODE)
CanTp_ConstructCFPci(uint8 ChannelIdx);

/*************************************************************************/
/*
 * Brief               Get the information of received FC frame.
 * ServiceId           N/A
 * Sync/Async          Synchronous
 * Reentrancy          Non Reentrant
 * Param-Name[in]      ChannelIdx index of channel
 * Param-Name[out]     FcInfoPtr information of the received FC
 * Param-Name[in/out]  N/A
 * Return              N/A
 * PreCondition        Module initialized, a FC received and the channel is
 *                     waiting for it.
 * CallByAPI           CanTp_MainFunction
 */
/*************************************************************************/
static FUNC(void, CANTP_CODE)
CanTp_GetChannelFCInfo(
    uint8 ChannelIdx,
    P2VAR(CanTp_FCInfoType, AUTOMATIC, AUTOMATIC) FcInfoPtr);


static FUNC(PduLengthType, CANTP_CODE)
CanTp_PaddingByFrameDL(uint8 ChannelIdx, PduLengthType frameDL);


static FUNC(void, CANTP_CODE)
CanTp_TxCFPadding(
	uint8 ChannelIdx,
	P2CONST(CanTp_TxNSduType, AUTOMATIC, CANTP_CONST) txSduCfgPtr,
	P2VAR(PduInfoType, AUTOMATIC, AUTOMATIC) pduInfoPtr
	);

static FUNC(void, CANTP_CODE)
CanTp_TxSFPadding(
	uint8 ChannelIdx,
#if (STD_ON == CANTP_FD)
	P2CONST(CanTp_TxNSduType, AUTOMATIC, CANTP_CONST) txSduCfgPtr,
#endif
	P2VAR(PduInfoType, AUTOMATIC, AUTOMATIC) pduInfoPtr
	);


static FUNC(Std_ReturnType, CANTP_CODE)
CanTp_CheckTxCanFDLength(
	P2CONST(CanTp_TxNSduType, AUTOMATIC, CANTP_CONST) TxNSduCfgPtr,
	PduLengthType sduTotalLength,
	PduLengthType dataFieldLength
	);


	
#define CANTP_STOP_SEC_CODE
#include "Cantp_MemMap.h"

/*=======[F U N C T I O N   I M P L E M E N T A T I O N S]====================*/
#define CANTP_START_SEC_CODE
#include "Cantp_MemMap.h"
/*************************************************************************/
/*
 * Brief               Get TX-SDU configuration by TX-NSduId.
 * ServiceId           N/A
 * Sync/Async          Synchronous
 * Reentrancy          Reentrant
 * Param-Name[in]      TxSduId ID of the TX SDU
 * Param-Name[out]     N/A
 * Param-Name[in/out]  N/A
 * Return              pointer to the configuration structure of this SDU
 *                     NULL_PTR if the no SDU matched with TxSduId
 * PreCondition        Module initialized
 * CallByAPI           CanTp Internal
 */
/*************************************************************************/
FUNC(P2CONST(CanTp_TxNSduType, AUTOMATIC, CANTP_CONST), CANTP_CODE)
CanTp_GetTxSduCfgByTxSduId(PduIdType TxSduId, uint8 *channelId)
{
    P2CONST(CanTp_TxNSduType, AUTOMATIC, CANTP_CONST) result = NULL_PTR;
    P2CONST(CanTp_ChannelType, AUTOMATIC, CANTP_VAR) channelPtr;
    uint8 sduIdx;
    uint8 chnIdx;

    for (chnIdx = 0; (NULL_PTR == result) && (chnIdx < CANTP_CHANNEL_NUMBER); chnIdx++)
    {
    	channelPtr = &CanTp_CfgData.CanTpChannel[chnIdx];
    	for (sduIdx = 0; (NULL_PTR == result) && (sduIdx < channelPtr->TxNsduNum); sduIdx++)
    	{
    		if (TxSduId == channelPtr->TxNSdus[sduIdx].TxNSduId)
    		{
    			result = &channelPtr->TxNSdus[sduIdx];
    			*channelId = chnIdx;
    		}
    	}
    }

    return result;
}

#if (STD_ON == CANTP_FD)
static FUNC(PduLengthType, CANTP_CODE)
CanTp_MatchDLC(PduLengthType frameDL)
{
	uint8 i;
	PduLengthType len;

	/*ISO 11898-1:2014 define the DLC table*/
	uint8 canDL[DLC_NUM] = {12, 16, 20, 24, 32, 48, 64};

	for (i = 0; i < DLC_NUM; i++)
	{
		if (frameDL <= canDL[i])
		{
			len = canDL[i];
			break;
		}
	}
	/**/
	return len;
}
#endif

static FUNC(PduLengthType, CANTP_CODE)
CanTp_PaddingByFrameDL(uint8 ChannelIdx, PduLengthType frameDL)
{
	PduLengthType position;

	position = CanTp_Channels[ChannelIdx].TxConnection.LocalDataPosition +
			CanTp_Channels[ChannelIdx].TxConnection.LocalDataLen;
	CanTp_MemorySet(
		&CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[position],
		CANTP_PADDING_BYTE,
		frameDL - position);

	return frameDL;
}

static FUNC(void, CANTP_CODE)
CanTp_TxCFPadding(
	uint8 ChannelIdx,
	P2CONST(CanTp_TxNSduType, AUTOMATIC, CANTP_CONST) txSduCfgPtr,
	P2VAR(PduInfoType, AUTOMATIC, AUTOMATIC) pduInfoPtr
	)
{
    PduLengthType frameDL;

	/*STmin timeout, send the CF immediately*/
	if (CAN20 == txSduCfgPtr->CanFrameType)
	{
		if (0u == CanTp_Channels[ChannelIdx].TxConnection.SduDataRemaining)
		{
			frameDL = CanTp_Channels[ChannelIdx].TxConnection.CanFrameLength;
			pduInfoPtr->SduLength = CanTp_PaddingByFrameDL(ChannelIdx, frameDL);
		}
	}
	#if (STD_ON == CANTP_FD)
	else
	{
		frameDL = CanTp_Channels[ChannelIdx].TxConnection.CanFrameLength;
		pduInfoPtr->SduLength = CanTp_PaddingByFrameDL(ChannelIdx, frameDL);
	}
	#endif
}

static FUNC(void, CANTP_CODE)
CanTp_TxSFPadding(
	uint8 ChannelIdx,
#if (STD_ON == CANTP_FD)
	P2CONST(CanTp_TxNSduType, AUTOMATIC, CANTP_CONST) txSduCfgPtr,
#endif
	P2VAR(PduInfoType, AUTOMATIC, AUTOMATIC) pduInfoPtr
	)
{
    PduLengthType frameDL;
#if (STD_ON == CANTP_FD)
    PduLengthType can20DataFieldLen;
    PduLengthType canFdDataOffset;


	switch (txSduCfgPtr->AddressingFormat)
	{
		case CANTP_STANDARD:
		{
			can20DataFieldLen = CANTP_SF_LEN_MAX_STD;
			canFdDataOffset = CANTP_SF_DATA_OFFSET_CANFD_STD;
			break;
		}
		#if (CANTP_EXTENDED_ADDRESSING_SUPPORT == STD_ON)
		case CANTP_EXTENDED:
		{
			can20DataFieldLen = CANTP_SF_LEN_MAX_EX;
			canFdDataOffset = CANTP_SF_DATA_OFFSET_CANFD_EX;
			break;
		}
		#endif
		#if (CANTP_NORMAL_FIXED_ADDRESSING_SUPPORT == STD_ON)
		case CANTP_NORMALFIXED:
		{
			can20DataFieldLen = CANTP_SF_LEN_MAX_NF;
			canFdDataOffset = CANTP_SF_DATA_OFFSET_CANFD_NF;
			break;
		}
		#endif
		#if (CANTP_MIXED_ADDRESSING_SUPPORT == STD_ON)
		case CANTP_MIXED:
		{
			can20DataFieldLen = CANTP_SF_LEN_MAX_MIX11;
			canFdDataOffset = CANTP_SF_DATA_OFFSET_CANFD_MIX11;
			break;
		}
		#endif
		#if (CANTP_MIXED29_ADDRESSING_SUPPORT == STD_ON)
		case CANTP_MIXED29BIT:
		{
			can20DataFieldLen = CANTP_SF_LEN_MAX_MIX29;
			canFdDataOffset = CANTP_SF_DATA_OFFSET_CANFD_MIX29;
			break;
		}
		#endif
		default:
			break;
	}

	if ((CanTp_Channels[ChannelIdx].TxConnection.SduDataTotalCount > can20DataFieldLen)
		&&( CAN_FD == txSduCfgPtr->CanFrameType))
	{
		/*CANFD frame length >8*/
		frameDL = CanTp_Channels[ChannelIdx].TxConnection.SduDataTotalCount + canFdDataOffset;
		/*frameDL here is less than or equal to the DLC which configuration in the CANFI module*/
		frameDL = CanTp_MatchDLC(frameDL);
		pduInfoPtr->SduLength = CanTp_PaddingByFrameDL(ChannelIdx, frameDL);
	}
	else
	#endif/*ENDOF #if (STD_ON == CANTP_FD)*/
	{
		/*CAN2.0 or small CAN FD*/
		frameDL = CanTp_Channels[ChannelIdx].TxConnection.CanFrameLength;
		pduInfoPtr->SduLength = CanTp_PaddingByFrameDL(ChannelIdx, frameDL);
	}
}

#if (CANTP_GENERIC_CONNECTION_SUPPORT == STD_ON)
FUNC(void, CANTP_CODE)CanTp_SaveTxMetaDataInfo(
	uint8 channelId,
	P2CONST(CanTp_TxNSduType, AUTOMATIC, CANTP_CONST) TxNSduCfgPtr,
	P2CONST(PduInfoType, AUTOMATIC, CANTP_APPL_CONST) CanTpTxInfoPtr
	)
{
#if ((CANTP_MIXED29_ADDRESSING_SUPPORT == STD_ON) \
	&& (CANTP_EXTENDED_ADDRESSING_SUPPORT == STD_ON) \
			&& (CANTP_MIXED_ADDRESSING_SUPPORT == STD_ON) \
			&& (CANTP_NORMAL_FIXED_ADDRESSING_SUPPORT == STD_ON))
	P2VAR(CanTp_ConnectionChannelType, AUTOMATIC, CANTP_VAR_POWER_ON_INIT) channelPtr = NULL_PTR;

	channelPtr = &CanTp_Channels[channelId];
#endif
	switch (TxNSduCfgPtr->AddressingFormat)
	{
		#if (CANTP_EXTENDED_ADDRESSING_SUPPORT == STD_ON)
		case CANTP_EXTENDED:
		{
			channelPtr->TxConnection.MetaDataN_TA = CanTpTxInfoPtr->SduDataPtr[CANTP_TA_OFFSET_META_EX];
			break;
		}
		#endif
		#if (CANTP_MIXED_ADDRESSING_SUPPORT == STD_ON)
		case CANTP_MIXED:
		{
			if (TxNSduCfgPtr->NAe != NULL_PTR)
			{
				channelPtr->TxConnection.MetaDataN_AE = *(TxNSduCfgPtr->NAe);
			}
			break;
		}
		#endif
		#if (CANTP_NORMAL_FIXED_ADDRESSING_SUPPORT == STD_ON)
		case CANTP_NORMALFIXED:
		{
			channelPtr->TxConnection.MetaDataN_SA = CanTpTxInfoPtr->SduDataPtr[CANTP_SA_OFFSET_META_NF];
			channelPtr->TxConnection.MetaDataN_TA = CanTpTxInfoPtr->SduDataPtr[CANTP_TA_OFFSET_META_NF];
			break;
		}
		#endif
		#if (CANTP_MIXED29_ADDRESSING_SUPPORT == STD_ON)
		case CANTP_MIXED29BIT:
		{
			channelPtr->TxConnection.MetaDataN_SA = CanTpTxInfoPtr->SduDataPtr[CANTP_SA_OFFSET_META_MIX29];
			channelPtr->TxConnection.MetaDataN_TA = CanTpTxInfoPtr->SduDataPtr[CANTP_TA_OFFSET_META_MIX29];
			if (TxNSduCfgPtr->NAe != NULL_PTR)
			{
				channelPtr->TxConnection.MetaDataN_AE = *(TxNSduCfgPtr->NAe);
			}
			break;
		}
		#endif
		default:
			break;
	}
}

static FUNC(void, CANTP_CODE)
CanTp_ConstructTxMetaDataInfo(
	uint8 channelId,
	P2CONST(CanTp_TxNSduType, AUTOMATIC, CANTP_CONST) TxNSduCfgPtr,
	P2VAR(PduInfoType, AUTOMATIC, AUTOMATIC) pduInfoPtr
	)
{
#if ((CANTP_MIXED29_ADDRESSING_SUPPORT == STD_ON) \
	&& (CANTP_EXTENDED_ADDRESSING_SUPPORT == STD_ON) \
			&& (CANTP_MIXED_ADDRESSING_SUPPORT == STD_ON) \
			&& (CANTP_NORMAL_FIXED_ADDRESSING_SUPPORT == STD_ON))
    PduLengthType position;

	position = pduInfoPtr->SduLength;
#endif
	switch (TxNSduCfgPtr->AddressingFormat)
	{
		#if (CANTP_EXTENDED_ADDRESSING_SUPPORT == STD_ON)
		case CANTP_EXTENDED:
		{
			break;
		}
		#endif
		#if (CANTP_MIXED_ADDRESSING_SUPPORT == STD_ON)
		case CANTP_MIXED:
		{
			break;
		}
		#endif
		#if (CANTP_NORMAL_FIXED_ADDRESSING_SUPPORT == STD_ON)
		case CANTP_NORMALFIXED:
		{
			pduInfoPtr->SduDataPtr[position] = CanTp_Channels[channelId].TxConnection.MetaDataN_TA;
			pduInfoPtr->SduDataPtr[position + 1u] = CanTp_Channels[channelId].TxConnection.MetaDataN_SA;
			pduInfoPtr->SduLength = pduInfoPtr->SduLength + 2u;
			break;
		}
		#endif
		#if (CANTP_MIXED29_ADDRESSING_SUPPORT == STD_ON)
		case CANTP_MIXED29BIT:
		{
			pduInfoPtr->SduDataPtr[position] = CanTp_Channels[channelId].TxConnection.MetaDataN_TA;
			pduInfoPtr->SduDataPtr[position + 1u] = CanTp_Channels[channelId].TxConnection.MetaDataN_SA;
			pduInfoPtr->SduLength = pduInfoPtr->SduLength + 2u;
			break;
		}
		#endif
		default:
			break;
	}
}

FUNC(Std_ReturnType, CANTP_CODE)
CanTp_CheckRxFCMetaData(
	uint8 channelIdx,
	P2CONST(CanTp_TxNSduType, AUTOMATIC, CANTP_CONST) TxNSduCfgPtr,
	P2CONST(PduInfoType, AUTOMATIC, CANTP_APPL_CONST) CanTpRxInfoPtr
	)
{
	   Std_ReturnType result = E_OK;
#if ((CANTP_MIXED29_ADDRESSING_SUPPORT == STD_ON) \
	&& (CANTP_EXTENDED_ADDRESSING_SUPPORT == STD_ON) \
			&& (CANTP_MIXED_ADDRESSING_SUPPORT == STD_ON) \
			&& (CANTP_NORMAL_FIXED_ADDRESSING_SUPPORT == STD_ON))
	   P2VAR(CanTp_ConnectionChannelType, AUTOMATIC, CANTP_VAR_POWER_ON_INIT) channelPtr = NULL_PTR;
	   
	   channelPtr = &CanTp_Channels[channelIdx];
#endif
	   switch (TxNSduCfgPtr->AddressingFormat)
	   	{
	   		#if (CANTP_EXTENDED_ADDRESSING_SUPPORT == STD_ON)
	   		case CANTP_EXTENDED:
	   		{
	   			if (channelPtr->RxConnection.MetaDataN_TA != CanTpRxInfoPtr->SduDataPtr[CANTP_TA_OFFSET_EX])
	   			{
	   				result = E_NOT_OK;
	   			}
	   			break;
	   		}
	   		#endif
	   		#if (CANTP_MIXED_ADDRESSING_SUPPORT == STD_ON)
	   		case CANTP_MIXED:
	   		{
	   			if (channelPtr->RxConnection.MetaDataN_AE != CanTpRxInfoPtr->SduDataPtr[CANTP_AE_OFFSET_MIX11])
				{
					result = E_NOT_OK;
				}
	   			break;
	   		}
	   		#endif
	   		#if (CANTP_NORMAL_FIXED_ADDRESSING_SUPPORT == STD_ON)
	   		case CANTP_NORMALFIXED:
	   		{
	   		    if ((channelPtr->RxConnection.MetaDataN_SA != CanTpRxInfoPtr->SduDataPtr[CanTpRxInfoPtr->SduLength - 1u])||
	   				(channelPtr->RxConnection.MetaDataN_TA != CanTpRxInfoPtr->SduDataPtr[CanTpRxInfoPtr->SduLength]))
	   		    {
	   			    result = E_NOT_OK;
	   		    }
	   			break;
	   		}
	   		#endif
	   		#if (CANTP_MIXED29_ADDRESSING_SUPPORT == STD_ON)
	   		case CANTP_MIXED29BIT:
	   		{
	   			if ((channelPtr->RxConnection.MetaDataN_AE != CanTpRxInfoPtr->SduDataPtr[CANTP_AE_OFFSET_MIX29])||
	   				(channelPtr->RxConnection.MetaDataN_SA != CanTpRxInfoPtr->SduDataPtr[CanTpRxInfoPtr->SduLength - 1u])||
					(channelPtr->RxConnection.MetaDataN_TA != CanTpRxInfoPtr->SduDataPtr[CanTpRxInfoPtr->SduLength]))
				{
					result = E_NOT_OK;
				}
	   			break;
	   		}
	   		#endif
	   		default:
	   			break;
	   	}
	   return result;
}
#endif

static FUNC(Std_ReturnType, CANTP_CODE)
CanTp_CheckTxCanFDLength(
	P2CONST(CanTp_TxNSduType, AUTOMATIC, CANTP_CONST) TxNSduCfgPtr,
	PduLengthType sduTotalLength,
	PduLengthType dataFieldLength
	)
{
	Std_ReturnType ret = E_NOT_OK;

	if (CAN_FD == TxNSduCfgPtr->CanFrameType)
	{
		if (dataFieldLength > sduTotalLength)
		{
			/*transmit each sdu length should less than DLC which configuration in Canif module*/
			ret = E_OK;
		}
		else
		{
			ret = E_NOT_OK;
		}
	}

	return ret;
}

FUNC(Std_ReturnType, CANTP_CODE)
CanTp_CheckTxLengthInAddressMode(
	P2CONST(CanTp_TxNSduType, AUTOMATIC, CANTP_CONST) TxNSduCfgPtr,
	P2CONST(PduInfoType, AUTOMATIC, CANTP_APPL_CONST) CanTpTxInfoPtr
	)
{
	Std_ReturnType ret = E_NOT_OK;
	PduLengthType len;

	switch (TxNSduCfgPtr->TxTaType)
	{
		/*functional addressing mode can only use SF*/
		case CANTP_FUNCTIONAL_TX:
		{
			switch (TxNSduCfgPtr->AddressingFormat)
			{
				case CANTP_STANDARD:
				{
					if (CANTP_SF_LEN_MAX_STD >= CanTpTxInfoPtr->SduLength)
					{
						/*CAN2.0 or small CAN FD can send this single frame*/
						ret = E_OK;
					}
					else
					{
						/*large CAN FD only*/
						len = TxNSduCfgPtr->TxNPduDLC - CANTP_SF_DATA_OFFSET_CANFD_STD;
						ret = CanTp_CheckTxCanFDLength(TxNSduCfgPtr, CanTpTxInfoPtr->SduLength, len);
					}
					break;
				}
				#if (CANTP_EXTENDED_ADDRESSING_SUPPORT == STD_ON)
				case CANTP_EXTENDED:
				{
					if (CANTP_SF_LEN_MAX_EX >= CanTpTxInfoPtr->SduLength)
					{
						/*CAN2.0 or small CAN FD*/
						ret = E_OK;
					}
					else
					{
						/*large CAN FD only*/
						len = TxNSduCfgPtr->TxNPduDLC - CANTP_SF_DATA_OFFSET_CANFD_EX;
						ret = CanTp_CheckTxCanFDLength(TxNSduCfgPtr, CanTpTxInfoPtr->SduLength, len);
					}
					break;
				}
				#endif
				#if (CANTP_NORMAL_FIXED_ADDRESSING_SUPPORT == STD_ON)
				case CANTP_NORMALFIXED:
				{
					if (CANTP_SF_LEN_MAX_NF >= CanTpTxInfoPtr->SduLength)
					{
						/*CAN2.0 or small CAN FD*/
						ret = E_OK;
					}
					else
					{
						/*large CAN FD only*/
						len = TxNSduCfgPtr->TxNPduDLC - CANTP_SF_DATA_OFFSET_CANFD_NF;
						ret = CanTp_CheckTxCanFDLength(TxNSduCfgPtr, CanTpTxInfoPtr->SduLength, len);
					}
					break;
				}
				#endif
				#if (CANTP_MIXED_ADDRESSING_SUPPORT == STD_ON)
				case CANTP_MIXED:
				{
					if (CANTP_SF_LEN_MAX_MIX11 >= CanTpTxInfoPtr->SduLength)
					{
						/*CAN2.0 or small CAN FD*/
						ret = E_OK;
					}
					else
					{
						/*large CAN FD only*/
						len = TxNSduCfgPtr->TxNPduDLC - CANTP_SF_DATA_OFFSET_CANFD_MIX11;
						ret = CanTp_CheckTxCanFDLength(TxNSduCfgPtr, CanTpTxInfoPtr->SduLength, len);
					}
					break;
				}
				#endif
				#if (CANTP_MIXED29_ADDRESSING_SUPPORT == STD_ON)
				case CANTP_MIXED29BIT:
				{
					if (CANTP_SF_LEN_MAX_CANFD_MIX29 >= CanTpTxInfoPtr->SduLength)
					{
						/*CAN2.0 or small CAN FD*/
						ret = E_OK;
					}
					else
					{
						/*large CAN FD only*/
						len = TxNSduCfgPtr->TxNPduDLC - CANTP_SF_DATA_OFFSET_CANFD_MIX29;
						ret = CanTp_CheckTxCanFDLength(TxNSduCfgPtr, CanTpTxInfoPtr->SduLength, len);
					}
					break;
				}
				#endif
				default:
					break;
			}
			break;
		}
		case CANTP_PHYSICAL_TX:
			ret = E_OK;
			break;
		default:
			break;
	}

	return ret;
}
/*************************************************************************/
/*
 * Brief               Get TX-SDU configuration by received FC NPDU information.
 * ServiceId           N/A
 * Sync/Async          Synchronous
 * Reentrancy          Non Reentrant
 * Param-Name[in]      CanTpRxPduId ID of the NPDU ID of received FC
 *                     CanTpRxPduPtr pointer to the data of received FC
 * Param-Name[out]     N/A
 * Param-Name[in/out]  N/A
 * Return              pointer to the configuration structure of this SDU
 *                     NULL_PTR if the no SDU matched
 * PreCondition        Module initialized
 * CallByAPI           CanTp Internal
 */
/*************************************************************************/
FUNC(P2CONST(CanTp_TxNSduType, AUTOMATIC, CANTP_CONST), CANTP_CODE)
CanTp_GetTxSduCfgByFCNpdu(	PduIdType CanTpRxPduId,
    						P2CONST(PduInfoType, AUTOMATIC, CANTP_APPL_CONST) CanTpRxPduPtr,
							P2VAR(uint8, AUTOMATIC, AUTOMATIC) channelIdx)
{
    P2CONST(CanTp_TxNSduType, AUTOMATIC, CANTP_CONST) result = NULL_PTR;
    P2CONST(CanTp_ChannelType, AUTOMATIC, CANTP_VAR) channelPtr;
    uint8 txNSduIdx;
    uint8 chnIdx;
    CanTp_FramePCIType frameType;
#if ((CANTP_MIXED29_ADDRESSING_SUPPORT == STD_ON) || (CANTP_MIXED_ADDRESSING_SUPPORT == STD_ON))
    boolean AEFlag = FALSE;
#endif
#if (CANTP_EXTENDED_ADDRESSING_SUPPORT == STD_ON)
    boolean TAFlag = FALSE;
#endif

	for (chnIdx = 0; (NULL_PTR == result) && (chnIdx < CANTP_CHANNEL_NUMBER); chnIdx++)
	{
		channelPtr = &CanTp_CfgData.CanTpChannel[chnIdx];
		for (txNSduIdx = 0; (NULL_PTR == result) && (txNSduIdx < channelPtr->TxNsduNum); txNSduIdx++)
		{
			/*only physical TX NSDU need configure RX FCNPDUID*/
			if (CANTP_PHYSICAL_TX == channelPtr->TxNSdus[txNSduIdx].TxTaType)
			{
				switch (channelPtr->TxNSdus[txNSduIdx].AddressingFormat)
				{
					case CANTP_STANDARD:
					{
						/*check the standard addressing TX-NSDU, only FC accepted*/
						frameType = CanTpRxPduPtr->SduDataPtr[CANTP_PCI_OFFSET_STD] & CANTP_FTYPE_MASK;
						if ((channelPtr->TxNSdus[txNSduIdx].RxFcNPduId == CanTpRxPduId)
							&& (CANTP_FTYPE_FC == frameType))
						{
							result = &channelPtr->TxNSdus[txNSduIdx];
							*channelIdx = chnIdx;
						}
						break;
					}
					#if (CANTP_EXTENDED_ADDRESSING_SUPPORT == STD_ON)
					case CANTP_EXTENDED:
					{
						if (CanTpRxPduPtr->SduLength > CANTP_PCI_OFFSET_EX)
						{
							/*check the extended addressing TX-NSDU, only FC accepted*/
							frameType = CanTpRxPduPtr->SduDataPtr[CANTP_PCI_OFFSET_EX] & CANTP_FTYPE_MASK;
							if ((channelPtr->TxNSdus[txNSduIdx].RxFcNPduId == CanTpRxPduId)
								&& (CANTP_FTYPE_FC == frameType))
							{
								if (channelPtr->TxNSdus[txNSduIdx].NTa != NULL_PTR)
								{
									if (*(channelPtr->TxNSdus[txNSduIdx].NTa) ==  CanTpRxPduPtr->SduDataPtr[CANTP_TA_OFFSET_EX])
									{
										TAFlag = TRUE;
									}
								}
								else
								{
									TAFlag = TRUE;
								}
								if (TRUE == TAFlag)
								{
									result = &channelPtr->TxNSdus[txNSduIdx];
									*channelIdx = chnIdx;
								}
							}
						}
						else
						{
							/*configured as extended addressing format, but the received NPDU not has enough data space*/
						}
						break;
					}
					#endif/*ENDOF #if (CANTP_EXTENDED_ADDRESSING_SUPPORT == STD_ON)*/
					#if (CANTP_NORMAL_FIXED_ADDRESSING_SUPPORT == STD_ON)
					case CANTP_NORMALFIXED:
					{
						/*check the normal fixed addressing TX-NSDU, only FC accepted*/
						frameType = CanTpRxPduPtr->SduDataPtr[CANTP_PCI_OFFSET_NF] & CANTP_FTYPE_MASK;
						if ((channelPtr->TxNSdus[txNSduIdx].RxFcNPduId == CanTpRxPduId)
							&& (CANTP_FTYPE_FC == frameType))
						{
							result = &channelPtr->TxNSdus[txNSduIdx];
							*channelIdx = chnIdx;
						}
						break;
					}
					#endif/*ENDOF #if (CANTP_NORMAL_FIXED_ADDRESSING_SUPPORT == STD_ON)*/
					#if (CANTP_MIXED_ADDRESSING_SUPPORT == STD_ON)
					case CANTP_MIXED:
					{
						if (CanTpRxPduPtr->SduLength > CANTP_PCI_OFFSET_MIX11)
						{
							/*check the mix11 addressing TX-NSDU, only FC accepted*/
							frameType = CanTpRxPduPtr->SduDataPtr[CANTP_PCI_OFFSET_MIX11] & CANTP_FTYPE_MASK;
							if ((channelPtr->TxNSdus[txNSduIdx].RxFcNPduId == CanTpRxPduId)
								&& (CANTP_FTYPE_FC == frameType))
							{
								if (channelPtr->TxNSdus[txNSduIdx].NAe != NULL_PTR)
								{
									if (*(channelPtr->TxNSdus[txNSduIdx].NAe) ==  CanTpRxPduPtr->SduDataPtr[CANTP_AE_OFFSET_MIX11])
									{
										AEFlag = TRUE;
									}
								}
								else
								{
									AEFlag = TRUE;
								}
								if (TRUE == AEFlag)
								{
									result = &channelPtr->TxNSdus[txNSduIdx];
									*channelIdx = chnIdx;
								}
							}
						}
						else
						{
							/*configured as extended addressing format, but the received NPDU not has enough data space*/
						}
						break;
					}
					#endif/*ENDOF #if (CANTP_MIXED_ADDRESSING_SUPPORT == STD_ON)*/
					#if (CANTP_MIXED29_ADDRESSING_SUPPORT == STD_ON)
					case CANTP_MIXED29BIT:
					{
						if (CanTpRxPduPtr->SduLength > CANTP_PCI_OFFSET_MIX29)
						{
							/*check the mix29 addressing TX-NSDU, only FC accepted*/
							frameType = CanTpRxPduPtr->SduDataPtr[CANTP_PCI_OFFSET_MIX29] & CANTP_FTYPE_MASK;
							if ((channelPtr->TxNSdus[txNSduIdx].RxFcNPduId == CanTpRxPduId)
								&& (CANTP_FTYPE_FC == frameType))
							{
								if (channelPtr->TxNSdus[txNSduIdx].NAe != NULL_PTR)
								{
									if (*(channelPtr->TxNSdus[txNSduIdx].NAe) ==  CanTpRxPduPtr->SduDataPtr[CANTP_AE_OFFSET_MIX29])
									{
										AEFlag = TRUE;
									}
								}
								else
								{
									AEFlag = TRUE;
								}
								if (TRUE == AEFlag)
								{
									result = &channelPtr->TxNSdus[txNSduIdx];
									*channelIdx = chnIdx;
								}
							}
						}
						else
						{
							/*configured as extended addressing format, but the received NPDU not has enough data space*/
						}
						break;
					}
					#endif/*ENDOF #if (CANTP_MIXED29_ADDRESSING_SUPPORT == STD_ON)*/
					default:
						break;
				}/*END OF switch*/
			} /*END OF if (CANTP_PHYSICAL == CanTp_CfgData.TxNSdus[txNSduIdx].TxTaType)*/
		}/*END OF for loop*/
	}/*END OF for loop*/

    return result;
}

/*************************************************************************/
/*
 * Brief               Get Tx-SDU configuration by Tx NPDUID.
 * ServiceId           N/A
 * Sync/Async          Synchronous
 * Reentrancy          Non Reentrant
 * Param-Name[in]      CanTpTxPduId ID of the data NPDU
 * Param-Name[out]     N/A
 * Param-Name[in/out]  N/A
 * Return              pointer to the configuration structure of this SDU
 *                     NULL_PTR if the no SDU matched
 * PreCondition        Module initialized
 * CallByAPI           CanTp Internal
 */
/*************************************************************************/
FUNC(P2CONST(CanTp_TxNSduType, AUTOMATIC, CANTP_CONST), CANTP_CODE)
CanTp_GetTxSduCfgByTxNPdu(PduIdType CanTpTxPduId, uint8 *channelId)
{
	P2CONST(CanTp_TxNSduType, AUTOMATIC, CANTP_CONST) result = NULL_PTR;
	P2CONST(CanTp_ChannelType, AUTOMATIC, CANTP_VAR) channelPtr;
	uint8 sduIdx;
	uint8 chnIdx;

	for (chnIdx = 0; (NULL_PTR == result) && (chnIdx < CANTP_CHANNEL_NUMBER); chnIdx++)
	{
		channelPtr = &CanTp_CfgData.CanTpChannel[chnIdx];
		for (sduIdx = 0; (NULL_PTR == result) && (sduIdx < channelPtr->TxNsduNum); sduIdx++)
		{
			if (CanTpTxPduId == channelPtr->TxNSdus[sduIdx].TxNPduId)
			{
				result = &channelPtr->TxNSdus[sduIdx];
				*channelId = chnIdx;
			}
		}
	}

	return result;
}

/*************************************************************************/
/*
 * Brief               Handle received FC.
 * ServiceId           N/A
 * Sync/Async          Synchronous
 * Reentrancy          Non Reentrant
 * Param-Name[in]      ChannelIdx channel index
 * Param-Name[out]     N/A
 * Param-Name[in/out]  N/A
 * Return              N/A
 * PreCondition        Module initialized, the channel is waiting for a FC from
 *                     the receiver, and FC received.
 * CallByAPI           CanTp_MainFunction
 */
/*************************************************************************/
FUNC(void, CANTP_CODE)
CanTp_TxHandleFCReception(uint8 ChannelIdx)
{
    CanTp_FCInfoType fcInfo;
    PduIdType nSduId;
    PduIdType iPduId;
    P2CONST(CanTp_TxNSduType, AUTOMATIC, CANTP_CONST) txNSduCfgPtr;
    uint32 N_Bs;
    uint32 N_Cs;
    uint8 channelId;

    CanTp_GetChannelFCInfo(ChannelIdx, &fcInfo);
    nSduId = CanTp_Channels[ChannelIdx].TxConnection.NSduId;
    txNSduCfgPtr = CanTp_GetTxSduCfgByTxSduId(nSduId, &channelId);
    iPduId = txNSduCfgPtr->TxIPduId;

    switch (fcInfo.FcFs)
    {
        case CANTP_FC_FS_CTS:
        {
            /*Clear to send. Get the channel ready to send CF, and make STmin timer timeout*/
            CanTp_ConstructCFPci(ChannelIdx);
            CanTp_Channels[ChannelIdx].TxConnection.CurrentBs = fcInfo.FcBS;
			CanTp_Channels[ChannelIdx].TxConnection.HandledCfCount = 0;
            CanTp_Channels[ChannelIdx].TxConnection.STminTimer.Started = TRUE;
            CanTp_Channels[ChannelIdx].TxConnection.STminTimer.RemainTime = fcInfo.FcSTMin;
            CanTp_Channels[ChannelIdx].TxConnection.STminTimer.StartTime = Frt_ReadOutMS();
            CanTp_Channels[ChannelIdx].TxConnection.STminTimer.FcSTMin = fcInfo.FcSTMin;
            /*transit to state SENDCF*/
            if (txNSduCfgPtr->Ncs != NULL_PTR)
            {
            	N_Cs = *(txNSduCfgPtr->Ncs);
                CanTp_Channels[ChannelIdx].TxConnection.ChannelTimer.EnabledTimer = CANTP_NC;
                CanTp_Channels[ChannelIdx].TxConnection.ChannelTimer.RemainTime = N_Cs;
                CanTp_Channels[ChannelIdx].TxConnection.ChannelTimer.StartTime = Frt_ReadOutMS();
            }
            else
            {
            	CanTp_Channels[ChannelIdx].TxConnection.ChannelTimer.EnabledTimer = CANTP_TIMER_NONE;
            }

            CanTp_Channels[ChannelIdx].TxConnection.HandleType = CANTP_FTYPE_CF;
            CanTp_Channels[ChannelIdx].TxConnection.Substate = CANTP_TX_LARGE_START;
            break;
        }
        case CANTP_FC_FS_WT:
        {
            /*reset the BS timer*/
            if (txNSduCfgPtr->Nbs != NULL_PTR)
            {
            	N_Bs = *(txNSduCfgPtr->Nbs);
                CanTp_Channels[ChannelIdx].TxConnection.ChannelTimer.EnabledTimer = CANTP_NB;
                CanTp_Channels[ChannelIdx].TxConnection.ChannelTimer.RemainTime = N_Bs;
                CanTp_Channels[ChannelIdx].TxConnection.ChannelTimer.StartTime = Frt_ReadOutMS();
            }
            else
            {
            	 CanTp_Channels[ChannelIdx].TxConnection.ChannelTimer.EnabledTimer = CANTP_TIMER_NONE;
            }
            break;
        }
        case CANTP_FC_FS_OVFLW:
        {
            /*No buffer in receiver*/
            /*release resource of channel*/
        	if (CanTp_Channels[ChannelIdx].ChannelMode == CANTP_MODE_HALF_DUPLEX)
        	{
        		CanTp_InitChannel(ChannelIdx);
        	}
        	else
        	{
        		CanTp_InitTxChannel(ChannelIdx);
        	}
            /*notify upper with NO_BUFFER*/
            PduR_CanTpTxConfirmation(iPduId, E_NOT_OK);
            break;
        }
        default:
        {
            /*Invalid FS value*/
            /*release resource of channel*/
        	if (CanTp_Channels[ChannelIdx].ChannelMode == CANTP_MODE_HALF_DUPLEX)
        	{
        		CanTp_InitChannel(ChannelIdx);
        	}
        	else
        	{
        		CanTp_InitTxChannel(ChannelIdx);
        	}
            /*notify upper with NO_BUFFER*/
            PduR_CanTpTxConfirmation(iPduId, E_NOT_OK);
            break;
        }
    } /*ENDOF switch (fcInfo.FcFs)*/

    /*clear event flag*/
    CanTp_Channels[ChannelIdx].TxConnection.EventFlags =
    		CanTp_Channels[ChannelIdx].TxConnection.EventFlags & ((uint8)~CANTP_CHANNEL_EVENT_FC_RECEIVED);
}

/*************************************************************************/
/*
 * Brief               Handle transmit request.
 * ServiceId           N/A
 * Sync/Async          Synchronous
 * Reentrancy          Non Reentrant
 * Param-Name[in]      ChannelIdx channel index
 * Param-Name[out]     N/A
 * Param-Name[in/out]  N/A
 * Return              N/A
 * PreCondition        Module initialized, the channel has accepted a transmitting
 *                     request.
 * CallByAPI           CanTp_MainFunction
 */
/*************************************************************************/
FUNC(void, CANTP_CODE)
CanTp_TxHandleTransmitReq(uint8 ChannelIdx)
{
    P2CONST(CanTp_TxNSduType, AUTOMATIC, CANTP_CONST) txNSduCfgPtr;
    PduLengthType len = 0;
    uint8 channelId;
    uint32 N_Cs;

    txNSduCfgPtr = CanTp_GetTxSduCfgByTxSduId(CanTp_Channels[ChannelIdx].TxConnection.NSduId, &channelId);

    if (CAN20 == txNSduCfgPtr->CanFrameType)
    {
    	/*Can2.0 or small Can Fd*/
		switch (txNSduCfgPtr->AddressingFormat)
		{
			case CANTP_STANDARD:
			{
				len = txNSduCfgPtr->TxNPduDLC - CANTP_SF_DATA_OFFSET_STD;
				break;
			}
			#if (CANTP_EXTENDED_ADDRESSING_SUPPORT == STD_ON)
			case CANTP_EXTENDED:
			{
				len = txNSduCfgPtr->TxNPduDLC - CANTP_SF_DATA_OFFSET_EX;
				break;
			}
			#endif
			#if (CANTP_NORMAL_FIXED_ADDRESSING_SUPPORT == STD_ON)
			case CANTP_NORMALFIXED:
			{
				len = txNSduCfgPtr->TxNPduDLC - CANTP_SF_DATA_OFFSET_NF;
				break;
			}
			#endif
			#if (CANTP_MIXED_ADDRESSING_SUPPORT == STD_ON)
			case CANTP_MIXED:
			{
				len = txNSduCfgPtr->TxNPduDLC - CANTP_SF_DATA_OFFSET_MIX11;
				break;
			}
			#endif
			#if (CANTP_MIXED29_ADDRESSING_SUPPORT == STD_ON)
			case CANTP_MIXED29BIT:
			{
				len = txNSduCfgPtr->TxNPduDLC - CANTP_SF_DATA_OFFSET_MIX29;
				break;
			}
			#endif
			default:
				break;
		}

    	if (len < CanTp_Channels[ChannelIdx].TxConnection.SduDataTotalCount)
		{
			/*larger SDU transmit request*/
			CanTp_Channels[ChannelIdx].TxConnection.HandleType = CANTP_FTYPE_FF;
			CanTp_Channels[ChannelIdx].TxConnection.RootState = CANTP_LARGE_TRANSMITTING;
			CanTp_Channels[ChannelIdx].TxConnection.Substate = CANTP_TX_LARGE_START;
		}
		else
		{
			/*SF transmit request*/
			CanTp_Channels[ChannelIdx].TxConnection.HandleType  = CANTP_FTYPE_SF;
			CanTp_Channels[ChannelIdx].TxConnection.RootState = CANTP_SF_TRANSIMITTING;
			CanTp_Channels[ChannelIdx].TxConnection.Substate = CANTP_TX_SF_START;
		}
    }
	#if (STD_ON == CANTP_FD)
    else
    {
    	/*CANFD*/
    	switch (txNSduCfgPtr->AddressingFormat)
		{
			case CANTP_STANDARD:
			{
				/*small Can FD data offset same as Can 2.0, CANTP_SF_DATA_OFFSET_STD,small Can FD data field length
				 * less than large Can FD, so len = bigger one*/
				len = txNSduCfgPtr->TxNPduDLC - CANTP_SF_DATA_OFFSET_CANFD_STD;
				break;
			}
			#if (CANTP_EXTENDED_ADDRESSING_SUPPORT == STD_ON)
			case CANTP_EXTENDED:
			{
				len = txNSduCfgPtr->TxNPduDLC - CANTP_SF_DATA_OFFSET_CANFD_EX;
				break;
			}
			#endif
			#if (CANTP_NORMAL_FIXED_ADDRESSING_SUPPORT == STD_ON)
			case CANTP_NORMALFIXED:
			{
				len = txNSduCfgPtr->TxNPduDLC - CANTP_SF_DATA_OFFSET_CANFD_NF;
				break;
			}
			#endif
			#if (CANTP_MIXED_ADDRESSING_SUPPORT == STD_ON)
			case CANTP_MIXED:
			{
				len = txNSduCfgPtr->TxNPduDLC - CANTP_SF_DATA_OFFSET_CANFD_MIX11;
				break;
			}
			#endif
			#if (CANTP_MIXED29_ADDRESSING_SUPPORT == STD_ON)
			case CANTP_MIXED29BIT:
			{
				len = txNSduCfgPtr->TxNPduDLC - CANTP_SF_DATA_OFFSET_CANFD_MIX29;
				break;
			}
			#endif
			default:
				break;
		}

    	if (len < CanTp_Channels[ChannelIdx].TxConnection.SduDataTotalCount)
		{
			/*larger SDU transmit request*/
			CanTp_Channels[ChannelIdx].TxConnection.HandleType = CANTP_FTYPE_FF;
			CanTp_Channels[ChannelIdx].TxConnection.RootState = CANTP_LARGE_TRANSMITTING;
			CanTp_Channels[ChannelIdx].TxConnection.Substate = CANTP_TX_LARGE_START;
		}
		else
		{
			/*SF transmit request*/
			CanTp_Channels[ChannelIdx].TxConnection.HandleType  = CANTP_FTYPE_SF;
			CanTp_Channels[ChannelIdx].TxConnection.RootState = CANTP_SF_TRANSIMITTING;
			CanTp_Channels[ChannelIdx].TxConnection.Substate = CANTP_TX_SF_START;
		}
    }
	#endif /*ENDOF #if (STD_ON == CANTP_FD)*/

    /*start CS timer*/
    if (txNSduCfgPtr->Ncs != NULL_PTR)
    {
    	N_Cs = *(txNSduCfgPtr->Ncs);
        CanTp_Channels[ChannelIdx].TxConnection.ChannelTimer.EnabledTimer = CANTP_NC;
        CanTp_Channels[ChannelIdx].TxConnection.ChannelTimer.RemainTime = N_Cs;
        CanTp_Channels[ChannelIdx].TxConnection.ChannelTimer.StartTime = Frt_ReadOutMS();
    }
    else
    {
    	CanTp_Channels[ChannelIdx].TxConnection.ChannelTimer.EnabledTimer = CANTP_TIMER_NONE;
    }
    /*construct PCI information*/
    if (CANTP_FTYPE_FF == CanTp_Channels[ChannelIdx].TxConnection.HandleType)
    {
        /*construct FF PCI information*/
        CanTp_ConstructFFPci(ChannelIdx);
    }
    else
    {
        /*construct SF PCI information*/
        CanTp_ConstructSFPci(ChannelIdx);
    }

    /*clear event flag*/
    CanTp_Channels[ChannelIdx].TxConnection.EventFlags = 0;
}

/*************************************************************************/
/*
 * Brief               Handle transmit cancel request event.
 * ServiceId           N/A
 * Sync/Async          Synchronous
 * Reentrancy          Non Reentrant
 * Param-Name[in]      ChannelIdx channel index
 * Param-Name[out]     N/A
 * Param-Name[in/out]  N/A
 * Return              N/A
 * PreCondition        Module initialized, the channel has accepted a cancel transmitting
 *                     request.
 * CallByAPI           CanTp_MainFunction
 */
/*************************************************************************/
FUNC(void, CANTP_CODE)
CanTp_TxHandleTransmitCancel(uint8 ChannelIdx)
{
    PduIdType sduId;
    PduIdType iPduId;
    uint8 channelId;
    P2CONST(CanTp_TxNSduType, AUTOMATIC, CANTP_CONST) txSduCfgPtr;

    sduId = CanTp_Channels[ChannelIdx].TxConnection.NSduId;
	txSduCfgPtr = CanTp_GetTxSduCfgByTxSduId(sduId, &channelId);
    iPduId = txSduCfgPtr->TxIPduId;

    /*Release the resource related with the channel*/
	if (CanTp_Channels[ChannelIdx].ChannelMode == CANTP_MODE_HALF_DUPLEX)
	{
		CanTp_InitChannel(ChannelIdx);
	}
	else
	{
		CanTp_InitTxChannel(ChannelIdx);
	}

    /*Notify the upper*/
    PduR_CanTpTxConfirmation(iPduId, E_NOT_OK);
}

/*************************************************************************/
/*
 * Brief               Handle confirmation for data transmit.
 * ServiceId           N/A
 * Sync/Async          Synchronous
 * Reentrancy          Non Reentrant
 * Param-Name[in]      ChannelIdx channel index
 * Param-Name[out]     N/A
 * Param-Name[in/out]  N/A
 * Return              N/A
 * PreCondition        Module initialized, the channel is waiting for a confirmation
 *                     of transmitted data.
 * CallByAPI           CanTp_MainFunction
 */
/*************************************************************************/
FUNC(void, CANTP_CODE)
CanTp_TxHandleTransmitCfm(uint8 ChannelIdx)
{
    PduIdType nSduId;
    PduIdType iPduId;
    uint8 channelId;
    P2CONST(CanTp_TxNSduType, AUTOMATIC, CANTP_CONST) txSduCfgPtr;
    uint32 N_Bs;
    uint32 N_Cs;

    nSduId = CanTp_Channels[ChannelIdx].TxConnection.NSduId;
    txSduCfgPtr = CanTp_GetTxSduCfgByTxSduId(nSduId, &channelId);
    iPduId = txSduCfgPtr->TxIPduId;

    if (CANTP_TX_SF_V4SF_CFM == CanTp_Channels[ChannelIdx].TxConnection.Substate)
    {
        /*Confirmation for SF data transmit. The end of the SF transmitting*/
        /*Release the channel resource*/
    	if (CanTp_Channels[ChannelIdx].ChannelMode == CANTP_MODE_HALF_DUPLEX)
    	{
    		CanTp_InitChannel(ChannelIdx);
    	}
    	else
    	{
    		CanTp_InitTxChannel(ChannelIdx);
    	}

        /*Notify the upper*/
        PduR_CanTpTxConfirmation(iPduId, E_OK);
    }
    else /*Confirmation for large SDU data transmit*/
    {
        /*update next SN number*/
        CanTp_Channels[ChannelIdx].TxConnection.CurrentCfSn =
        		(uint8)(CanTp_Channels[ChannelIdx].TxConnection.CurrentCfSn + 1u) & CANTP_CF_SN_MASK;

        if (CANTP_FTYPE_FF == CanTp_Channels[ChannelIdx].TxConnection.HandleType)
        {
            /*confirmation for FF, transit to state V4FC and start BS timer*/
            CanTp_Channels[ChannelIdx].TxConnection.Substate = CANTP_TX_LARGE_V4FC;
            if (txSduCfgPtr->Nbs != NULL_PTR)
            {
            	N_Bs = *(txSduCfgPtr->Nbs);
                CanTp_Channels[ChannelIdx].TxConnection.ChannelTimer.EnabledTimer = CANTP_NB;
                CanTp_Channels[ChannelIdx].TxConnection.ChannelTimer.RemainTime = N_Bs;
                CanTp_Channels[ChannelIdx].TxConnection.ChannelTimer.StartTime = Frt_ReadOutMS();
            }
            else
            {
            	CanTp_Channels[ChannelIdx].TxConnection.ChannelTimer.EnabledTimer = CANTP_TIMER_NONE;
            }
        }
        else /*confirmation for CF*/
        {
            if (0u == CanTp_Channels[ChannelIdx].TxConnection.SduDataRemaining)
            {
                /*SDU transmitting finished*/
                /*release resource of channel*/
            	if (CanTp_Channels[ChannelIdx].ChannelMode == CANTP_MODE_HALF_DUPLEX)
            	{
            		CanTp_InitChannel(ChannelIdx);
            	}
            	else
            	{
            		CanTp_InitTxChannel(ChannelIdx);
            	}
                /*notify the upper*/
                PduR_CanTpTxConfirmation(iPduId, E_OK);
            }
            else /*whole SDU transmitting not finished*/
            {
                /*update handled CF count*/
                if (0xFFu > CanTp_Channels[ChannelIdx].TxConnection.HandledCfCount)
                {
                    CanTp_Channels[ChannelIdx].TxConnection.HandledCfCount++;
                }

                if (CanTp_Channels[ChannelIdx].TxConnection.HandledCfCount == CanTp_Channels[ChannelIdx].TxConnection.CurrentBs)
                {
                    /*current block finished*/
                    /*wait another FC*/
                    CanTp_Channels[ChannelIdx].TxConnection.Substate = CANTP_TX_LARGE_V4FC;
                    if (txSduCfgPtr->Nbs != NULL_PTR)
                    {
                    	N_Bs = *(txSduCfgPtr->Nbs);
                        CanTp_Channels[ChannelIdx].TxConnection.ChannelTimer.EnabledTimer = CANTP_NB;
                        CanTp_Channels[ChannelIdx].TxConnection.ChannelTimer.RemainTime = N_Bs;
                        CanTp_Channels[ChannelIdx].TxConnection.ChannelTimer.StartTime = Frt_ReadOutMS();
                    }
                    else
                    {
                    	CanTp_Channels[ChannelIdx].TxConnection.ChannelTimer.EnabledTimer = CANTP_TIMER_NONE;
                    }
                }
                else /*current block not finished yet*/
                {
                    /*construct the next CF PCI, and transit to SENDCF, start STmin and CS*/
                    CanTp_ConstructCFPci(ChannelIdx);
                    CanTp_Channels[ChannelIdx].TxConnection.Substate = CANTP_TX_LARGE_START;
                    if (txSduCfgPtr->Ncs != NULL_PTR)
                    {
                    	N_Cs = *(txSduCfgPtr->Ncs);
                        CanTp_Channels[ChannelIdx].TxConnection.ChannelTimer.EnabledTimer = CANTP_NC;
                        CanTp_Channels[ChannelIdx].TxConnection.ChannelTimer.RemainTime = N_Cs;
                        CanTp_Channels[ChannelIdx].TxConnection.ChannelTimer.StartTime = Frt_ReadOutMS();
                    }
                    else
                    {
                    	CanTp_Channels[ChannelIdx].TxConnection.ChannelTimer.EnabledTimer = CANTP_TIMER_NONE;
                    }

                    CanTp_Channels[ChannelIdx].TxConnection.STminTimer.Started = TRUE;
                    CanTp_Channels[ChannelIdx].TxConnection.STminTimer.RemainTime =
                    		CanTp_Channels[ChannelIdx].TxConnection.STminTimer.FcSTMin;
                    CanTp_Channels[ChannelIdx].TxConnection.STminTimer.StartTime = Frt_ReadOutMS();
                }
            } /*ENDOF whole SDU transmitting not finished*/
        } /*END OF confirmation for CF*/
    } /*END OF Confirmation for large SDU data transmit*/

    /*clear event flag*/
    CanTp_Channels[ChannelIdx].TxConnection.EventFlags =
    		CanTp_Channels[ChannelIdx].TxConnection.EventFlags & ((uint8)~CANTP_CHANNEL_EVENT_TX_CONFIRMED);
}

/*************************************************************************/
/*
 * Brief               Back ground handling for SF transmitting.
 * ServiceId           N/A
 * Sync/Async          Synchronous
 * Reentrancy          Non Reentrant
 * Param-Name[in]      ChannelIdx channel index
 * Param-Name[out]     N/A
 * Param-Name[in/out]  N/A
 * Return              N/A
 * PreCondition        Module initialized, the channel is trying to get TX buffer
 *                     so that can transmit the SF.
 * CallByAPI           CanTp_MainFunction
 */
/*************************************************************************/
FUNC(void, CANTP_CODE)
CanTp_TxHandleSFStart(uint8 ChannelIdx)
{
    PduInfoType pduInfo;
    P2VAR(PduInfoType, AUTOMATIC, AUTOMATIC) pduInfoPtr = &pduInfo;
    P2CONST(CanTp_TxNSduType, AUTOMATIC, CANTP_CONST) txSduCfgPtr;
    BufReq_ReturnType bufRslt;
    Std_ReturnType rslt;
    PduLengthType position;
    PduIdType nSduId;
    PduIdType iPduId;
    uint8 channelId;

    nSduId = CanTp_Channels[ChannelIdx].TxConnection.NSduId;
	txSduCfgPtr = CanTp_GetTxSduCfgByTxSduId(nSduId, &channelId);
    iPduId = txSduCfgPtr->TxIPduId;
    position = CanTp_Channels[ChannelIdx].TxConnection.LocalDataPosition;
    pduInfo.SduDataPtr = &CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[position];
	if (CAN20 == txSduCfgPtr->CanFrameType)
	{
		/*CAN2.0*/
		if (txSduCfgPtr->TxNPduDLC > CANTP_CAN20_FRAME_LEN_MAX)
		{
			CanTp_Channels[ChannelIdx].TxConnection.CanFrameLength = CANTP_CAN20_FRAME_LEN_MAX;
		}
		else
		{
			CanTp_Channels[ChannelIdx].TxConnection.CanFrameLength = txSduCfgPtr->TxNPduDLC;
		}
	}
	#if (STD_ON == CANTP_FD)
	else
	{
		CanTp_Channels[ChannelIdx].TxConnection.CanFrameLength = txSduCfgPtr->TxNPduDLC;
	}
	#endif
	pduInfo.SduLength = CanTp_Channels[ChannelIdx].TxConnection.CanFrameLength -
			CanTp_Channels[ChannelIdx].TxConnection.LocalDataPosition;

    /*SF may less than the length of CAN Frame*/
	if (pduInfo.SduLength > CanTp_Channels[ChannelIdx].TxConnection.SduDataRemaining)
	{
		pduInfo.SduLength = CanTp_Channels[ChannelIdx].TxConnection.SduDataRemaining;
	}

    /*upperBufRemaining is upper layer data left after copy data*/
    bufRslt = PduR_CanTpCopyTxData(iPduId, pduInfoPtr, NULL_PTR, &CanTp_Channels[ChannelIdx].TxConnection.UpperBufRemaining);

    /*Handle according to the request buffer result*/
    switch (bufRslt)
    {
        case BUFREQ_OK:
        {
            /*get length of the data copy*/
        	CanTp_Channels[ChannelIdx].TxConnection.SduDataRemaining =
        			CanTp_Channels[ChannelIdx].TxConnection.SduDataRemaining - pduInfo.SduLength;

            CanTp_Channels[ChannelIdx].TxConnection.LocalDataLen = pduInfo.SduLength;

            if (0u == CanTp_Channels[ChannelIdx].TxConnection.SduDataRemaining)
            {
                /*SF data copy finished, send it*/
                /*construct CANIF transmit request*/
                pduInfo.SduDataPtr = CanTp_Channels[ChannelIdx].TxConnection.LocalBuf;
                pduInfo.SduLength = CanTp_Channels[ChannelIdx].TxConnection.LocalDataPosition +
                		CanTp_Channels[ChannelIdx].TxConnection.LocalDataLen;
        		/*pduInfo.SduLength will be set in the api below, if padding*/
        		if (CANTP_PADDING_ON == txSduCfgPtr->TxPaddingActivation)
        		{
        			CanTp_TxSFPadding(ChannelIdx,
#if (STD_ON == CANTP_FD)
        			        txSduCfgPtr,
#endif
        			        &pduInfo);
        		}

				#if (CANTP_GENERIC_CONNECTION_SUPPORT == STD_ON)
                if (CanTp_Channels[ChannelIdx].TxConnection.MetaDataLength > 0u)
                {
                	CanTp_ConstructTxMetaDataInfo(ChannelIdx, txSduCfgPtr, pduInfoPtr);
                }
				#endif

                CanTp_Channels[ChannelIdx].TxConnection.Substate = CANTP_TX_SF_V4SF_CFM;  /*chenms 2013-9-26 19:32*/
                /*Request CANIF to transmit the SF frame*/
                rslt = CanIf_Transmit(txSduCfgPtr->TxLPduId, pduInfoPtr);
                if (E_NOT_OK == rslt)
                {
                	 /*Release resources related to the channel*/
                	if (CanTp_Channels[ChannelIdx].ChannelMode == CANTP_MODE_HALF_DUPLEX)
                	{
                		CanTp_InitChannel(ChannelIdx);
                	}
                	else
                	{
                		CanTp_InitTxChannel(ChannelIdx);
                	}

                    /*Notify the upper*/
                    PduR_CanTpTxConfirmation(iPduId, E_NOT_OK);
                }
                else
                {
                	/*Transit channel to wait for confirmation of SF*/
					CanTp_Channels[ChannelIdx].TxConnection.Substate = CANTP_TX_SF_V4SF_CFM;
					CanTp_Channels[ChannelIdx].TxConnection.ChannelTimer.EnabledTimer = CANTP_NA;
					CanTp_Channels[ChannelIdx].TxConnection.ChannelTimer.RemainTime = txSduCfgPtr->Nas;
					CanTp_Channels[ChannelIdx].TxConnection.ChannelTimer.StartTime = Frt_ReadOutMS();
                }
            } /*END OF SF data copy finished*/
            break;
        } /*ENDOF case BUFREQ_OK*/
        case BUFREQ_E_NOT_OK:
        {
            /*Fail to get TX buffer*/
            /*Release resources related to the channel*/
        	if (CanTp_Channels[ChannelIdx].ChannelMode == CANTP_MODE_HALF_DUPLEX)
        	{
        		CanTp_InitChannel(ChannelIdx);
        	}
        	else
        	{
        		CanTp_InitTxChannel(ChannelIdx);
        	}

            /*Notify the upper*/
            PduR_CanTpTxConfirmation(iPduId, E_NOT_OK);
            break;
        }
        case BUFREQ_E_BUSY:
            /*The upper is busy, no buffer provided. Try to get buffer next round*/
            break;
        default:
            /*invalid return value for PduR_CanTpProvideTxBuffer*/
            break;
    } /*END OF switch*/
}

/*************************************************************************/
/*
 * Brief               Back ground handling for large SDU transmitting, trying to get TX buffer.
 * ServiceId           N/A
 * Sync/Async          Synchronous
 * Reentrancy          Non Reentrant
 * Param-Name[in]      ChannelIdx channel index
 * Param-Name[out]     N/A
 * Param-Name[in/out]  N/A
 * Return              N/A
 * PreCondition        Module initialized, the channel is trying to get TX buffer
 *                     so that can transmit the FF or CF.
 * CallByAPI           CanTp_MainFunction
 */
/*************************************************************************/
FUNC(void, CANTP_CODE)
CanTp_TxHandleLargeStart(uint8 ChannelIdx)
{
    PduInfoType pduInfo;
    P2VAR(PduInfoType, AUTOMATIC, AUTOMATIC) pduInfoPtr = &pduInfo;
    P2CONST(CanTp_TxNSduType, AUTOMATIC, CANTP_CONST) txSduCfgPtr;
    BufReq_ReturnType bufRslt;
    Std_ReturnType rslt;
    PduLengthType position;
    PduIdType nSduId;
    PduIdType iPduId;
    uint8 channelId;
    static VAR(boolean, CANTP_VAR_POWER_ON_INIT) CopyFlg = FALSE;

    nSduId = CanTp_Channels[ChannelIdx].TxConnection.NSduId;
    txSduCfgPtr = CanTp_GetTxSduCfgByTxSduId(nSduId, &channelId);
    iPduId = txSduCfgPtr->TxIPduId;
    pduInfo.SduLength = 0;

    /*calculate the length which need to be copied*/
    if (CAN20 == txSduCfgPtr->CanFrameType)
	{
		/*CAN2.0*/
		if (txSduCfgPtr->TxNPduDLC > CANTP_CAN20_FRAME_LEN_MAX)
		{
			CanTp_Channels[ChannelIdx].TxConnection.CanFrameLength = CANTP_CAN20_FRAME_LEN_MAX;
		}
		else
		{
			CanTp_Channels[ChannelIdx].TxConnection.CanFrameLength = txSduCfgPtr->TxNPduDLC;
		}
	}
	#if (STD_ON == CANTP_FD)
	else
	{
		CanTp_Channels[ChannelIdx].TxConnection.CanFrameLength = txSduCfgPtr->TxNPduDLC;
	}
	#endif
	if ((CANTP_FTYPE_FF == CanTp_Channels[ChannelIdx].TxConnection.HandleType)
		|| ((CopyFlg == FALSE) && (CANTP_FTYPE_FF != CanTp_Channels[ChannelIdx].TxConnection.HandleType)))
	{
		pduInfo.SduLength = CanTp_Channels[ChannelIdx].TxConnection.CanFrameLength -
				CanTp_Channels[ChannelIdx].TxConnection.LocalDataPosition;

		/*the last CF may less than the length of CAN Frame*/
		if (pduInfo.SduLength > CanTp_Channels[ChannelIdx].TxConnection.SduDataRemaining)
		{
			pduInfo.SduLength = CanTp_Channels[ChannelIdx].TxConnection.SduDataRemaining;
		}
		position = CanTp_Channels[ChannelIdx].TxConnection.LocalDataPosition;
		pduInfo.SduDataPtr = &CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[position];
		bufRslt = PduR_CanTpCopyTxData(iPduId, pduInfoPtr, NULL_PTR, &CanTp_Channels[ChannelIdx].TxConnection.UpperBufRemaining);
	}
	else
	{
		bufRslt = BUFREQ_OK;
	}

    switch (bufRslt)
    {
        case BUFREQ_OK:
        {

        	if ((CANTP_FTYPE_FF == CanTp_Channels[ChannelIdx].TxConnection.HandleType)
        	    || ((CopyFlg == FALSE) && (CANTP_FTYPE_FF != CanTp_Channels[ChannelIdx].TxConnection.HandleType)))
        	{
				/*update channel runtime information*/
				/*get length of the data copy*/
				CanTp_Channels[ChannelIdx].TxConnection.LocalDataLen = pduInfo.SduLength;
				CanTp_Channels[ChannelIdx].TxConnection.SduDataRemaining =
						CanTp_Channels[ChannelIdx].TxConnection.SduDataRemaining - pduInfo.SduLength;
        	}
	        /*Set CopyFlg*/
	        CopyFlg = TRUE;
			if (CANTP_FTYPE_FF == CanTp_Channels[ChannelIdx].TxConnection.HandleType)
			{
				/*send the FF immediately*/
				pduInfo.SduDataPtr = CanTp_Channels[ChannelIdx].TxConnection.LocalBuf;
				/*the length include pci info*/
				pduInfo.SduLength = CanTp_Channels[ChannelIdx].TxConnection.LocalDataLen +
						CanTp_Channels[ChannelIdx].TxConnection.LocalDataPosition;

				#if (CANTP_GENERIC_CONNECTION_SUPPORT == STD_ON)
                if (CanTp_Channels[ChannelIdx].TxConnection.MetaDataLength > 0u)
                {
                	CanTp_ConstructTxMetaDataInfo(ChannelIdx, txSduCfgPtr, pduInfoPtr);
                }
				#endif

				CanTp_Channels[ChannelIdx].TxConnection.Substate = CANTP_TX_LARGE_V4DATA_CFM;   /*chenms 2013-9-26 19:32*/
				rslt = CanIf_Transmit(txSduCfgPtr->TxLPduId, pduInfoPtr);
	        	/*Clear CopyFlg*/
	        	CopyFlg = FALSE;
				if (E_NOT_OK == rslt)
				{
		        	if (CanTp_Channels[ChannelIdx].ChannelMode == CANTP_MODE_HALF_DUPLEX)
		        	{
		        		CanTp_InitChannel(ChannelIdx);
		        	}
		        	else
		        	{
		        		CanTp_InitTxChannel(ChannelIdx);
		        	}

                    /*Notify the upper*/
                    PduR_CanTpTxConfirmation(iPduId, E_NOT_OK);
				}
				else
				{
					/*Transit channel to wait for confirmation of FF*/
					CanTp_Channels[ChannelIdx].TxConnection.Substate = CANTP_TX_LARGE_V4DATA_CFM;
					CanTp_Channels[ChannelIdx].TxConnection.ChannelTimer.EnabledTimer = CANTP_NA;
					CanTp_Channels[ChannelIdx].TxConnection.ChannelTimer.RemainTime = txSduCfgPtr->Nas;
					CanTp_Channels[ChannelIdx].TxConnection.ChannelTimer.StartTime = Frt_ReadOutMS();
				}
			}
			else /*handle the CF transmitting data copy*/
			{
				if ((TRUE == CanTp_Channels[ChannelIdx].TxConnection.STminTimer.Started)
					&& (0u == CanTp_Channels[ChannelIdx].TxConnection.STminTimer.RemainTime))
				{
					pduInfo.SduDataPtr = CanTp_Channels[ChannelIdx].TxConnection.LocalBuf;
					pduInfo.SduLength = CanTp_Channels[ChannelIdx].TxConnection.LocalDataPosition +
							CanTp_Channels[ChannelIdx].TxConnection.LocalDataLen;
	        		/*pduInfo.SduLength will be set in the api below*/
					if (CANTP_PADDING_ON == txSduCfgPtr->TxPaddingActivation)
					{
						CanTp_TxCFPadding(ChannelIdx, txSduCfgPtr, pduInfoPtr);
					}

					#if (CANTP_GENERIC_CONNECTION_SUPPORT == STD_ON)
	                if (CanTp_Channels[ChannelIdx].TxConnection.MetaDataLength > 0u)
	                {
	                	CanTp_ConstructTxMetaDataInfo(ChannelIdx, txSduCfgPtr, pduInfoPtr);
	                }
					#endif

					CanTp_Channels[ChannelIdx].TxConnection.Substate = CANTP_TX_LARGE_V4DATA_CFM;   /*chenms 2013-9-26 19:32*/
					rslt = CanIf_Transmit(txSduCfgPtr->TxLPduId, pduInfoPtr);
		        	/*Clear CopyFlg*/
		        	CopyFlg = FALSE;
					if (E_NOT_OK == rslt)
					{
			        	if (CanTp_Channels[ChannelIdx].ChannelMode == CANTP_MODE_HALF_DUPLEX)
			        	{
			        		CanTp_InitChannel(ChannelIdx);
			        	}
			        	else
			        	{
			        		CanTp_InitTxChannel(ChannelIdx);
			        	}

	                    /*Notify the upper*/
	                    PduR_CanTpTxConfirmation(iPduId, E_NOT_OK);
					}
					else
					{
						/*Transit channel to wait for confirmation of CF*/
						CanTp_Channels[ChannelIdx].TxConnection.Substate = CANTP_TX_LARGE_V4DATA_CFM;
						CanTp_Channels[ChannelIdx].TxConnection.ChannelTimer.EnabledTimer = CANTP_NA;
						CanTp_Channels[ChannelIdx].TxConnection.ChannelTimer.RemainTime = txSduCfgPtr->Nas;
						CanTp_Channels[ChannelIdx].TxConnection.ChannelTimer.StartTime = Frt_ReadOutMS();
					}

					CanTp_Channels[ChannelIdx].TxConnection.STminTimer.Started = FALSE;
				}
				else /*STmin not time out*/
				{
					/*transit to state SENDCF, wait for sending next round*/
				}
			} /*END OF handle the CF transmitting data copy*/
            break;
        } /*ENDOF case BUFREQ_OK*/
        case BUFREQ_E_NOT_OK:
        {
            /*Fail to get TX buffer*/
            /*Release resources related to the channel*/
        	if (CanTp_Channels[ChannelIdx].ChannelMode == CANTP_MODE_HALF_DUPLEX)
        	{
        		CanTp_InitChannel(ChannelIdx);
        	}
        	else
        	{
        		CanTp_InitTxChannel(ChannelIdx);
        	}

            /*Notify the upper*/
            PduR_CanTpTxConfirmation(iPduId, E_NOT_OK);

            break;
        }
        case BUFREQ_E_BUSY:
    		if ((CANTP_NC == CanTp_Channels[ChannelIdx].TxConnection.ChannelTimer.EnabledTimer)
    				&&(0u == CanTp_Channels[ChannelIdx].TxConnection.ChannelTimer.RemainTime))
			{
        		/*SWS_CanTp_00167,STmin timeout, abort send*/
        		/*Release resources related to the channel*/
            	if (CanTp_Channels[ChannelIdx].ChannelMode == CANTP_MODE_HALF_DUPLEX)
            	{
            		CanTp_InitChannel(ChannelIdx);
            	}
            	else
            	{
            		CanTp_InitTxChannel(ChannelIdx);
            	}
        		/*SWS_CanTp_00280,Notify the upper*/
				PduR_CanTpTxConfirmation(iPduId, E_NOT_OK);
			}
            /*The upper is busy, no buffer provided. Try to get buffer next round*/
            break;
        default:
            /*invalid return value*/
            break;
    } /*END OF switch (bufRslt)*/
}

/*============Internal static Function Implementation*/
/*************************************************************************/
/*
 * Brief               construct FF PCI information in local buffer for channel.
 * ServiceId           N/A
 * Sync/Async          Synchronous
 * Reentrancy          Non Reentrant
 * Param-Name[in]      ChannelIdx index of channel
 * Param-Name[out]     N/A
 * Param-Name[in/out]  N/A
 * Return              N/A
 * PreCondition        Module initialized, need to construct FF.
 * CallByAPI           CanTp_MainFunction
 */
/*************************************************************************/
static FUNC(void, CANTP_CODE)
CanTp_ConstructFFPci(uint8 ChannelIdx)
{
    P2CONST(CanTp_TxNSduType, AUTOMATIC, CANTP_CONST) txNSduCfgPtr;
    uint32 pciDl;
    uint8 channelId;

    txNSduCfgPtr = CanTp_GetTxSduCfgByTxSduId(CanTp_Channels[ChannelIdx].TxConnection.NSduId, &channelId);
    pciDl = CanTp_Channels[ChannelIdx].TxConnection.SduDataTotalCount;

    if (CANTP_STANDARD == txNSduCfgPtr->AddressingFormat)
    {
    	/*standard FF*/
    	if (pciDl <= CANTP_FF_DL_12bit_LENGTH)
    	{
    		/*FF_DL less than or equal to 4095*/
    		/*SDU length low nibble*/
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_FF_FFDL_LOW_OFFSET_LT4095_STD] = (uint8)pciDl;
			/*SDU length high nibble and Frame type*/
			pciDl >>= CANTP_OFFSET_BYTE_PART;
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_PCI_OFFSET_STD] = CANTP_FTYPE_FF|(uint8)pciDl;
			/*update local information*/
			CanTp_Channels[ChannelIdx].TxConnection.LocalDataPosition = CANTP_FF_DATA_OFFSET_LT4095_STD;
    	}
    	else
    	{
    		/*FF_DL bigger than 4095*/
			/*SDU length from low to high nibble*/
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_FF_FFDL_LOW_OFFSET_BT4095_STD] = (uint8)pciDl;
			pciDl >>= CANTP_OFFSET_BYTE_PART;
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_FF_FFDL_LOW_OFFSET_BT4095_STD - 1u] = (uint8)pciDl;
			pciDl >>= CANTP_OFFSET_BYTE_PART;
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_FF_FFDL_LOW_OFFSET_BT4095_STD - 2u] = (uint8)pciDl;
			pciDl >>= CANTP_OFFSET_BYTE_PART;
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_FF_FFDL_LOW_OFFSET_BT4095_STD - 3u] = (uint8)pciDl;
			/*SDU Frame type*/
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_PCI_OFFSET_STD] = CANTP_FTYPE_FF;
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_PCI_OFFSET_STD + 1u] = 0x00;
			/*update local information*/
			CanTp_Channels[ChannelIdx].TxConnection.LocalDataPosition = CANTP_FF_DATA_OFFSET_BT4095_STD;
    	}
    }
	#if (CANTP_EXTENDED_ADDRESSING_SUPPORT == STD_ON)
    else if (CANTP_EXTENDED == txNSduCfgPtr->AddressingFormat)
    {
        /*extended FF*/
    	if (pciDl <= CANTP_FF_DL_12bit_LENGTH)
		{
			/*FF_DL less than or equal to 4095*/
			/*SDU length low nibble*/
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_FF_FFDL_LOW_OFFSET_LT4095_EX] = (uint8)pciDl;
			/*SDU length high nibble and Frame type*/
			pciDl >>= CANTP_OFFSET_BYTE_PART;
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_PCI_OFFSET_EX] = CANTP_FTYPE_FF|(uint8)pciDl;
			/*update local information*/
			CanTp_Channels[ChannelIdx].TxConnection.LocalDataPosition = CANTP_FF_DATA_OFFSET_LT4095_EX;
		}
		else
		{
			/*FF_DL bigger than 4095*/
			/*SDU length from low to high nibble*/
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_FF_FFDL_LOW_OFFSET_BT4095_EX] = (uint8)pciDl;
			pciDl >>= CANTP_OFFSET_BYTE_PART;
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_FF_FFDL_LOW_OFFSET_BT4095_EX - 1u] = (uint8)pciDl;
			pciDl >>= CANTP_OFFSET_BYTE_PART;
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_FF_FFDL_LOW_OFFSET_BT4095_EX - 2u] = (uint8)pciDl;
			pciDl >>= CANTP_OFFSET_BYTE_PART;
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_FF_FFDL_LOW_OFFSET_BT4095_EX - 3u] = (uint8)pciDl;
			/*SDU Frame type*/
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_PCI_OFFSET_EX] = CANTP_FTYPE_FF;
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_PCI_OFFSET_EX + 1u] = 0x00u;
			/*update local information*/
			CanTp_Channels[ChannelIdx].TxConnection.LocalDataPosition = CANTP_FF_DATA_OFFSET_BT4095_EX;
		}
    }
	#endif
	#if (CANTP_NORMAL_FIXED_ADDRESSING_SUPPORT == STD_ON)
	else if (CANTP_NORMALFIXED == txNSduCfgPtr->AddressingFormat)
	{
		if (pciDl <= CANTP_FF_DL_12bit_LENGTH)
		{
			/*FF_DL less than or equal to 4095*/
			/*SDU length low nibble*/
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_FF_FFDL_LOW_OFFSET_LT4095_NF] = (uint8)pciDl;
			/*SDU length high nibble and Frame type*/
			pciDl >>= CANTP_OFFSET_BYTE_PART;
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_PCI_OFFSET_NF] = CANTP_FTYPE_FF|(uint8)pciDl;
			/*update local information*/
			CanTp_Channels[ChannelIdx].TxConnection.LocalDataPosition = CANTP_FF_DATA_OFFSET_LT4095_NF;
		}
		else
		{
			/*FF_DL bigger than 4095*/
			/*SDU length from low to high nibble*/
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_FF_FFDL_LOW_OFFSET_BT4095_NF] = (uint8)pciDl;
			pciDl >>= CANTP_OFFSET_BYTE_PART;
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_FF_FFDL_LOW_OFFSET_BT4095_NF - 1u] = (uint8)pciDl;
			pciDl >>= CANTP_OFFSET_BYTE_PART;
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_FF_FFDL_LOW_OFFSET_BT4095_NF - 2u] = (uint8)pciDl;
			pciDl >>= CANTP_OFFSET_BYTE_PART;
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_FF_FFDL_LOW_OFFSET_BT4095_NF - 3u] = (uint8)pciDl;
			/*SDU Frame type*/
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_PCI_OFFSET_NF] = CANTP_FTYPE_FF;
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_PCI_OFFSET_NF + 1u] = 0x00u;
			/*update local information*/
			CanTp_Channels[ChannelIdx].TxConnection.LocalDataPosition = CANTP_FF_DATA_OFFSET_BT4095_NF;
		}
	}
	#endif
	#if (CANTP_MIXED_ADDRESSING_SUPPORT == STD_ON)
	else if (CANTP_MIXED == txNSduCfgPtr->AddressingFormat)
	{
		if (pciDl <= CANTP_FF_DL_12bit_LENGTH)
		{
			/*FF_DL less than or equal to 4095*/
			/*SDU length low nibble*/
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_FF_FFDL_LOW_OFFSET_LT4095_MIX11] = (uint8)pciDl;
			/*SDU length high nibble and Frame type*/
			pciDl >>= CANTP_OFFSET_BYTE_PART;
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_PCI_OFFSET_MIX11] = CANTP_FTYPE_FF|(uint8)pciDl;
			/*update local information*/
			CanTp_Channels[ChannelIdx].TxConnection.LocalDataPosition = CANTP_FF_DATA_OFFSET_LT4095_MIX11;
		}
		else
		{
			/*FF_DL bigger than 4095*/
			/*SDU length from low to high nibble*/
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_FF_FFDL_LOW_OFFSET_BT4095_MIX11] = (uint8)pciDl;
			pciDl >>= CANTP_OFFSET_BYTE_PART;
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_FF_FFDL_LOW_OFFSET_BT4095_MIX11 - 1u] = (uint8)pciDl;
			pciDl >>= CANTP_OFFSET_BYTE_PART;
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_FF_FFDL_LOW_OFFSET_BT4095_MIX11 - 2u] = (uint8)pciDl;
			pciDl >>= CANTP_OFFSET_BYTE_PART;
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_FF_FFDL_LOW_OFFSET_BT4095_MIX11 - 3u] = (uint8)pciDl;
			/*SDU Frame type*/
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_PCI_OFFSET_MIX11] = CANTP_FTYPE_FF;
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_PCI_OFFSET_MIX11 + 1u] = 0x00u;
			/*update local information*/
			CanTp_Channels[ChannelIdx].TxConnection.LocalDataPosition = CANTP_FF_DATA_OFFSET_BT4095_MIX11;
		}
	}
	#endif
	#if (CANTP_MIXED29_ADDRESSING_SUPPORT == STD_ON)
	else if (CANTP_MIXED29BIT == txNSduCfgPtr->AddressingFormat)
	{
		if (pciDl <= CANTP_FF_DL_12bit_LENGTH)
		{
			/*FF_DL less than or equal to 4095*/
			/*SDU length low nibble*/
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_FF_FFDL_LOW_OFFSET_LT4095_MIX29] = (uint8)pciDl;
			/*SDU length high nibble and Frame type*/
			pciDl >>= CANTP_OFFSET_BYTE_PART;
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_PCI_OFFSET_MIX29] = CANTP_FTYPE_FF|(uint8)pciDl;
			/*update local information*/
			CanTp_Channels[ChannelIdx].TxConnection.LocalDataPosition = CANTP_FF_DATA_OFFSET_LT4095_MIX29;
		}
		else
		{
			/*FF_DL bigger than 4095*/
			/*SDU length from low to high nibble*/
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_FF_FFDL_LOW_OFFSET_BT4095_MIX29] = (uint8)pciDl;
			pciDl >>= CANTP_OFFSET_BYTE_PART;
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_FF_FFDL_LOW_OFFSET_BT4095_MIX29 - 1u] = (uint8)pciDl;
			pciDl >>= CANTP_OFFSET_BYTE_PART;
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_FF_FFDL_LOW_OFFSET_BT4095_MIX29 - 2u] = (uint8)pciDl;
			pciDl >>= CANTP_OFFSET_BYTE_PART;
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_FF_FFDL_LOW_OFFSET_BT4095_MIX29 - 3u] = (uint8)pciDl;
			/*SDU Frame type*/
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_PCI_OFFSET_MIX29] = CANTP_FTYPE_FF;
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_PCI_OFFSET_MIX29 + 1u] = 0x00u;
			/*update local information*/
			CanTp_Channels[ChannelIdx].TxConnection.LocalDataPosition = CANTP_FF_DATA_OFFSET_BT4095_MIX29;
		}
	}
	else
	{}
	#endif
}

/*************************************************************************/
/*
 * Brief               construct SF PCI information in local buffer for channel.
 * ServiceId           N/A
 * Sync/Async          Synchronous
 * Reentrancy          Non Reentrant
 * Param-Name[in]      ChannelIdx index of channel
 * Param-Name[out]     N/A
 * Param-Name[in/out]  N/A
 * Return              N/A
 * PreCondition        Module initialized, need to construct SF.
 * CallByAPI           CanTp_MainFunction
 */
/*************************************************************************/
static FUNC(void, CANTP_CODE)
CanTp_ConstructSFPci(uint8 ChannelIdx)
{
    P2CONST(CanTp_TxNSduType, AUTOMATIC, CANTP_CONST) txNSduCfgPtr;
    uint16 pciDl;
    uint8 channelId;

    txNSduCfgPtr = CanTp_GetTxSduCfgByTxSduId(CanTp_Channels[ChannelIdx].TxConnection.NSduId, &channelId);
    pciDl = CanTp_Channels[ChannelIdx].TxConnection.SduDataTotalCount;

    if (CANTP_STANDARD == txNSduCfgPtr->AddressingFormat)
    {
        /*standard SF*/
    	if (pciDl <= CANTP_SF_LEN_MAX_STD)
    	{
    		/*SF_DL less than or equal to 7*/
    		/*Frame type and SF DL*/
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_PCI_OFFSET_STD] =
					((uint8)pciDl & CANTP_SF_DL_MASK);/*CANTP_FTYPE_SF*/
			/*update local buffer information*/
			CanTp_Channels[ChannelIdx].TxConnection.LocalDataPosition = CANTP_SF_DATA_OFFSET_STD;
    	}
		#if (STD_ON == CANTP_FD)
    	else
    	{
    		/*SF_DL bigger than 7*/
    		/*Frame type and SF DL*/
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_PCI_OFFSET_STD] = CANTP_FTYPE_SF;
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_PCI_OFFSET_STD + 1u] = (uint8)pciDl;
			/*update local buffer information*/
			CanTp_Channels[ChannelIdx].TxConnection.LocalDataPosition = CANTP_SF_DATA_OFFSET_CANFD_STD;
    	}
		#endif/*ENDOF #if (STD_ON == CANTP_FD)*/
    }
	#if (CANTP_EXTENDED_ADDRESSING_SUPPORT == STD_ON)
    else if (CANTP_EXTENDED == txNSduCfgPtr->AddressingFormat)
    {
    	/*extended SF*/
    	if (pciDl <= CANTP_SF_LEN_MAX_EX)
    	{
    		/*SF_DL less than or equal to 7*/
    		/*Frame type and SF DL*/
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_PCI_OFFSET_EX] =
					CANTP_FTYPE_SF | ((uint8)pciDl & CANTP_SF_DL_MASK);
			/*update local buffer information*/
			CanTp_Channels[ChannelIdx].TxConnection.LocalDataPosition = CANTP_SF_DATA_OFFSET_EX;
    	}
		#if (STD_ON == CANTP_FD)
    	else
    	{
    		/*SF_DL bigger than 7*/
    		/*Frame type and SF DL*/
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_PCI_OFFSET_EX] = CANTP_FTYPE_SF;
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_PCI_OFFSET_EX + 1u] = (uint8)pciDl;
			/*update local buffer information*/
			CanTp_Channels[ChannelIdx].TxConnection.LocalDataPosition = CANTP_SF_DATA_OFFSET_CANFD_EX;
    	}
		#endif/*ENDOF #if (STD_ON == CANTP_FD)*/
    }
	#endif
	#if (CANTP_NORMAL_FIXED_ADDRESSING_SUPPORT == STD_ON)
	else if (CANTP_NORMALFIXED == txNSduCfgPtr->AddressingFormat)
	{
		if (pciDl <= CANTP_SF_LEN_MAX_NF)
		{
			/*SF_DL less than or equal to 7*/
			/*Frame type and SF DL*/
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_PCI_OFFSET_NF] =
					CANTP_FTYPE_SF | ((uint8)pciDl & CANTP_SF_DL_MASK);
			/*update local buffer information*/
			CanTp_Channels[ChannelIdx].TxConnection.LocalDataPosition = CANTP_SF_DATA_OFFSET_NF;
		}
		#if (STD_ON == CANTP_FD)
		else
		{
			/*SF_DL bigger than 7*/
			/*Frame type and SF DL*/
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_PCI_OFFSET_NF] = CANTP_FTYPE_SF;
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_PCI_OFFSET_NF + 1u] = (uint8)pciDl;
			/*update local buffer information*/
			CanTp_Channels[ChannelIdx].TxConnection.LocalDataPosition = CANTP_SF_DATA_OFFSET_CANFD_NF;
		}
		#endif/*ENDOF #if (STD_ON == CANTP_FD)*/
	}
	#endif
	#if (CANTP_MIXED_ADDRESSING_SUPPORT == STD_ON)
	else if (CANTP_MIXED == txNSduCfgPtr->AddressingFormat)
	{
		if (pciDl <= CANTP_SF_LEN_MAX_MIX11)
		{
			/*SF_DL less than or equal to 7*/
			/*Frame type and SF DL*/
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_PCI_OFFSET_MIX11] =
					CANTP_FTYPE_SF | ((uint8)pciDl & CANTP_SF_DL_MASK);
			/*update local buffer information*/
			CanTp_Channels[ChannelIdx].TxConnection.LocalDataPosition = CANTP_SF_DATA_OFFSET_MIX11;
		}
		#if (STD_ON == CANTP_FD)
		else
		{
			/*SF_DL bigger than 7*/
			/*Frame type and SF DL*/
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_PCI_OFFSET_MIX11] = CANTP_FTYPE_SF;
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_PCI_OFFSET_MIX11 + 1u] = (uint8)pciDl;
			/*update local buffer information*/
			CanTp_Channels[ChannelIdx].TxConnection.LocalDataPosition = CANTP_SF_DATA_OFFSET_CANFD_MIX11;
		}
		#endif/*ENDOF #if (STD_ON == CANTP_FD)*/
	}
	#endif
	#if (CANTP_MIXED29_ADDRESSING_SUPPORT == STD_ON)
	else if (CANTP_MIXED29BIT == txNSduCfgPtr->AddressingFormat)
	{
		if (pciDl <= CANTP_SF_LEN_MAX_MIX29)
		{
			/*SF_DL less than or equal to 7*/
			/*Frame type and SF DL*/
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_PCI_OFFSET_MIX29] =
					CANTP_FTYPE_SF | ((uint8)pciDl & CANTP_SF_DL_MASK);
			/*update local buffer information*/
			CanTp_Channels[ChannelIdx].TxConnection.LocalDataPosition = CANTP_SF_DATA_OFFSET_MIX29;
		}
		#if (STD_ON == CANTP_FD)
		else
		{
			/*SF_DL bigger than 7*/
			/*Frame type and SF DL*/
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_PCI_OFFSET_MIX29] = CANTP_FTYPE_SF;
			CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_PCI_OFFSET_MIX29 + 1u] = (uint8)pciDl;
			/*update local buffer information*/
			CanTp_Channels[ChannelIdx].TxConnection.LocalDataPosition = CANTP_SF_DATA_OFFSET_CANFD_MIX29;
		}
		#endif/*ENDOF #if (STD_ON == CANTP_FD)*/
	}
	#endif
	else
	{}
}

/*************************************************************************/
/*
 * Brief               construct CF PCI information in local buffer for channel.
 * ServiceId           N/A
 * Sync/Async          Synchronous
 * Reentrancy          Non Reentrant
 * Param-Name[in]      ChannelIdx index of channel
 * Param-Name[out]     N/A
 * Param-Name[in/out]  N/A
 * Return              N/A
 * PreCondition        Module initialized, need to construct CF.
 * CallByAPI           CanTp_MainFunction
 */
/*************************************************************************/
static FUNC(void, CANTP_CODE)
CanTp_ConstructCFPci(uint8 ChannelIdx)
{
    P2CONST(CanTp_TxNSduType, AUTOMATIC, CANTP_CONST) txNSduCfgPtr;
    uint8 channelId;

    txNSduCfgPtr = CanTp_GetTxSduCfgByTxSduId(CanTp_Channels[ChannelIdx].TxConnection.NSduId, &channelId);

    if (CANTP_STANDARD == txNSduCfgPtr->AddressingFormat)
    {
        /*Standard SDU*/
        CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_PCI_OFFSET_STD] =
        		CANTP_FTYPE_CF | CanTp_Channels[ChannelIdx].TxConnection.CurrentCfSn;
        /*update local buffer information*/
        CanTp_Channels[ChannelIdx].TxConnection.LocalDataPosition = CANTP_CF_DATA_OFFSET_STD;
    }
	#if (CANTP_EXTENDED_ADDRESSING_SUPPORT == STD_ON)
    else if (CANTP_EXTENDED == txNSduCfgPtr->AddressingFormat)
    {
        CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_PCI_OFFSET_EX] =
        		CANTP_FTYPE_CF | CanTp_Channels[ChannelIdx].TxConnection.CurrentCfSn;
        /*update local buffer information*/
        CanTp_Channels[ChannelIdx].TxConnection.LocalDataPosition = CANTP_CF_DATA_OFFSET_EX;
    }
	#endif
	#if (CANTP_NORMAL_FIXED_ADDRESSING_SUPPORT == STD_ON)
	else if (CANTP_NORMALFIXED == txNSduCfgPtr->AddressingFormat)
	{
		CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_PCI_OFFSET_NF] =
				CANTP_FTYPE_CF | CanTp_Channels[ChannelIdx].TxConnection.CurrentCfSn;
		/*update local buffer information*/
		CanTp_Channels[ChannelIdx].TxConnection.LocalDataPosition = CANTP_CF_DATA_OFFSET_NF;
	}
	#endif
	#if (CANTP_MIXED_ADDRESSING_SUPPORT == STD_ON)
	else if (CANTP_MIXED == txNSduCfgPtr->AddressingFormat)
	{
		CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_PCI_OFFSET_MIX11] =
				CANTP_FTYPE_CF | CanTp_Channels[ChannelIdx].TxConnection.CurrentCfSn;
		/*update local buffer information*/
		CanTp_Channels[ChannelIdx].TxConnection.LocalDataPosition = CANTP_CF_DATA_OFFSET_MIX11;
	}
	#endif
	#if (CANTP_MIXED29_ADDRESSING_SUPPORT == STD_ON)
	else if (CANTP_MIXED29BIT == txNSduCfgPtr->AddressingFormat)
	{
		CanTp_Channels[ChannelIdx].TxConnection.LocalBuf[CANTP_PCI_OFFSET_MIX29] =
				CANTP_FTYPE_CF | CanTp_Channels[ChannelIdx].TxConnection.CurrentCfSn;
		/*update local buffer information*/
		CanTp_Channels[ChannelIdx].TxConnection.LocalDataPosition = CANTP_CF_DATA_OFFSET_MIX29;
	}
	#endif
	else
	{}
}

/*************************************************************************/
/*
 * Brief               Get the information of received FC frame.
 * ServiceId           N/A
 * Sync/Async          Synchronous
 * Reentrancy          Non Reentrant
 * Param-Name[in]      ChannelIdx index of channel
 * Param-Name[out]     FcInfoPtr information of the received FC
 * Param-Name[in/out]  N/A
 * Return              N/A
 * PreCondition        Module initialized, a FC received and the channel is
 *                     waiting for it.
 * CallByAPI           CanTp_MainFunction
 */
/*************************************************************************/
static FUNC(void, CANTP_CODE)
CanTp_GetChannelFCInfo(
    uint8 ChannelIdx,
    P2VAR(CanTp_FCInfoType, AUTOMATIC, AUTOMATIC) FcInfoPtr)
{
    P2CONST(CanTp_TxNSduType, AUTOMATIC, CANTP_CONST) txNSduCfgPtr;
	uint32 stMinUs;
    uint8 channelId;
    PduLengthType offset = 0;
    uint8 stMinRaw;


    txNSduCfgPtr = CanTp_GetTxSduCfgByTxSduId(CanTp_Channels[ChannelIdx].TxConnection.NSduId, &channelId);

    if (CANTP_STANDARD == txNSduCfgPtr->AddressingFormat)
    {
        /*standard SDU*/
        offset = CANTP_PCI_OFFSET_STD;
    }
	#if (CANTP_EXTENDED_ADDRESSING_SUPPORT == STD_ON)
    else if (CANTP_EXTENDED == txNSduCfgPtr->AddressingFormat)
    {
        /*extended SDU*/
        offset = CANTP_PCI_OFFSET_EX;
    }
	#endif
	#if (CANTP_NORMAL_FIXED_ADDRESSING_SUPPORT == STD_ON)
	else if (CANTP_NORMALFIXED == txNSduCfgPtr->AddressingFormat)
	{
		/*extended SDU*/
		offset = CANTP_PCI_OFFSET_NF;
	}
	#endif
	#if (CANTP_MIXED_ADDRESSING_SUPPORT == STD_ON)
	else if (CANTP_MIXED == txNSduCfgPtr->AddressingFormat)
	{
		/*extended SDU*/
		offset = CANTP_PCI_OFFSET_MIX11;
	}
	#endif
	#if (CANTP_MIXED29_ADDRESSING_SUPPORT == STD_ON)
	else if (CANTP_MIXED29BIT == txNSduCfgPtr->AddressingFormat)
	{
		/*extended SDU*/
		offset = CANTP_PCI_OFFSET_MIX29;
	}
	#endif
	else
	{
	    /*idle*/
	}

    FcInfoPtr->FcFs = CanTp_Channels[ChannelIdx].TxConnection.FcBuf[offset] & CANTP_FC_FS_MASK;
    FcInfoPtr->FcBS = CanTp_Channels[ChannelIdx].TxConnection.FcBuf[offset + 1u];

    /*calculate the STMin in tick unit. Round the value to the nearest integer, that is
     * if it is 0.49, then the integer will be 0, 0.50 will be 1.*/
    stMinRaw = CanTp_Channels[ChannelIdx].TxConnection.FcBuf[offset + 2u];

    if (CANTP_FC_STMIN_MS_LIMIT >= stMinRaw)
    {
        /*ms per bit*/
        stMinUs = (uint32)stMinRaw * CANTP_FC_STMIN_MS_UNIT;
    }
    else if ((CANTP_FC_STMIN_US_LOW <= stMinRaw)
        && (CANTP_FC_STMIN_US_UPPER >= stMinRaw))
    {
        /*F1-F9 100us per step*/
        stMinUs = ((uint32)((uint32)stMinRaw - 0xF0UL)) * CANTP_FC_STMIN_US_UNIT;
    }
    else
    {
        /*invalid value, use 7F*/
        stMinUs = (uint32)CANTP_FC_STMIN_MS_LIMIT * CANTP_FC_STMIN_MS_UNIT;
    }

    /*transit to value in unit tick*/
    FcInfoPtr->FcSTMin = (stMinUs + (uint32)((uint32)1000 >> (uint32)1)) / (uint32)1000;
}

#define CANTP_STOP_SEC_CODE
#include "Cantp_MemMap.h"
/*=======[E N D   O F   F I L E]==============================================*/
